1. 程式人生 > >[HDU3535] [2010多校聯考10] AreYouBusy [分組揹包][01揹包]

[HDU3535] [2010多校聯考10] AreYouBusy [分組揹包][01揹包]

[ L i n k \frak{Link} ]


三種物品集合,第一種至少選一個,第二種至多選一個,第三種隨便選。
第三種不帶約束的很簡單,01

揹包就可以了。
其它兩種分別是兩類分組揹包。
需要注意的是ci, gi≥0。注意為0的情況,不要重複計算。
三個子問題都是經典的,尤其是兩個分組揹包如果沒有做過應該瞭解一下。
其中有兩個子問題如果單獨考慮是可以滾動的。


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int n,T;
int m[105], s[105];
int c[105][105], g[105][105];
int F[105][105];
int
main() { while (~scanf("%d%d", &n, &T)) { for (int i = 1; i <= n; ++i) { scanf("%d%d", &m[i], &s[i]); for (int j = 1; j <= m[i]; ++j) { scanf("%d%d", &c[i][j], &g[i][j]); } } memset(F, 0, sizeof(F)); for (int i = 1; i <= n; ++i) { if (s[i] ==
0) memset(F[i], 0xcf, sizeof(F[i])); else memcpy(F[i], F[i-1], sizeof(F[i-1])); for (int k = 1; k <= m[i]; ++k) { for (int j = T; j >= 0; --j) { if (j < c[i][k]) continue; if (s[i] == 0) { F[i][j] = max(F[i][j], F[i][j-c[i][k]] + g[i][k]); F[i][j] = max(F[i][j], F[i-1][j-c[i][k]] + g[i][k]); } else { if (s[i] == 1) F[i][j] = max(F[i][j], F[i-1][j-c[i][k]] + g[i][k]); if (s[i] == 2) F[i][j] = max(F[i][j], F[i][j-c[i][k]] + g[i][k]); } } } } printf( "%d\n", max(F[n][T],-1) ); } return 0; } } } } printf( "%d\n", max(F[n][T],-1) ); } return 0; }