所謂分組揹包,就是將物品分組,每組的物品相互衝突,最多隻能選一個物品放進去1。相對於0/1揹包增加了分組。
本文將介紹類似0/1揹包的方式。回顧0/1揹包的方式,表示前個物品中總重量不大於的最大價值,轉移式是
分組揹包中,依然用(此處的意義變化了),i表示前i組揹包,一組揹包中可能有很多個互斥物品。轉移式是
其中zs[i]表示第i個物品所在的組。
有以下注意點:
- 第組可能包括很多個互斥物品,因此可能被多次用到,需要取max。
- 轉移的時候要按順序轉移,把第組(包括很多個互斥物品)處理完了以後再處理第組。
代碼如下:
/* ***********************************************
Author : VFVrPQ
Created Time : 六 2/29 18:57:01 2020
File Name : luogu1757通天之分組揹包.cpp
Problem :
Description :
Solution :
Tag :
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
#define DEBUG(x) cout<<x<<endl;
const int N = 1e5+10;
const int M = 1e9+7;
const int INF = 1e9+7;
int n, m;
struct Node{
int a,b,c;
};
Node p[N];
bool cmp(Node i, Node j){
return i.c<j.c;
}
int dp[N][1111];//dp[i][j]表示前i組,最大重量是j時的最大價值(注意是前i組!)
int main()
{
scanf("%d%d",&m,&n);
for (int i=1;i<=n;i++){
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
}
sort(p+1, p+n+1, cmp);//按組號排序
for (int i=1;i<=n;i++){
for (int j=0;j<=m;j++){
int zs = p[i].c;//組數
//因爲可能不同的物品屬於同一組,所以dp[zs][j]會被不同的物品多次更新,需要取max
if (j<p[i].a) dp[zs][j] = max(dp[zs][j], dp[zs-1][j]);//從前一組轉移過來
else {
dp[zs][j] = max(dp[zs][j], max(dp[zs-1][j], dp[zs-1][j-p[i].a]+p[i].b));
}
}
}
int max_zs = p[n].c;
printf("%d\n", dp[max_zs][m]);
return 0;
}