分组背包题目
hdu 1712 ACboy needs your help 分组背包入门题目
http://acm.hdu.edu.cn/showproblem.php?pid=1712
题意:
acboy今年有n门课程,给出每门课程他授课多少天能获得的利润,w[i][j]表示第i个课程他如果授课j天可获得的利润,求在m天内它能够获得最大利润。
思路:
每门课程看做一个分组,每门课程对应着m个物品可选,直接套用分组背包即可。
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a , b) ((a) < (b) ? (a) : (b)) #define Max(a , b) ((a) > (b) ? (a) : (b)) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 107 #define N 107 using namespace std; //freopen("din.txt","r",stdin); int f[N]; int w[N][N]; int main(){ // freopen("din.txt","r",stdin); int i,j,k; int n,m; while (~scanf("%d%d",&n,&m)){ if (!n && !m) break; for (i = 1; i <= n; ++i){ for (j = 1; j <= m; ++j) scanf("%d",&w[i][j]); } CL(f,0); for (i = 1; i <= n; ++i){ for (j = m; j >= 1; --j){ for (k = 1; k <= j; ++k){//注意这里小于等于j f[j] = max(f[j],f[j - k] + w[i][k]); } } } printf("%d\n",f[m]); } return 0; }
hdu 3033 I love sneakers! 变形的分组背包(好题)
http://acm.hdu.edu.cn/showproblem.php?pid=3033
题意:
给出n个鞋子,每个鞋子分别对应着买它需要的费用,以及买完后获得的价值。这n个鞋子总共有m种品牌,保证每种品牌至少选择一个,求可能获得的最大价值。
思路:
这里保证每种品牌至少选择一个买了,所以才开始我利用num[i][j]表示到达i状态第j中品牌是否选了。而且也是空间优化到一维的结果超时了,算了算肯定超时。后来看了一下解题报告,才明白的。
首先f[i][j]表示选择了前i种商品,用了j的钱数所能得到的最大值,由于每种品牌至少选择一个所以只要把for循环变换一下即可保证能够多选某种品牌,但是这里怎么样保证由上一状态来的状态肯定选择了i-1呢,所以我们只需要dp[i - 1][j] != -1的因为这样的状态保证选择i-1这种状态,回想一下01背包的时候它会把-1覆盖成上一状态值,而这里不需要,还有这里c可能为0,我们必须首先保证最后计算由上一状态转移到该状态的值,否则如果先计算的话,就可能会造成一双鞋子买了多遍。。。
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a , b) ((a) < (b) ? (a) : (b)) #define Max(a , b) ((a) > (b) ? (a) : (b)) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 10007 #define N 12 using namespace std; //freopen("din.txt","r",stdin); struct node{ int c,w; }tp; int f[N][M]; vector<node>vc[N]; int Get(){ char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); int num = 0; while (ch >= '0' && ch <= '9'){ num = num*10 + ch - '0'; ch = getchar(); } return num; } int main(){ //freopen("din.txt","r",stdin); int i,j,k; int n,V,m; int a,b,c; while (~scanf("%d%d%d",&n,&V,&m)){ for (i = 0; i <= m; ++i) vc[i].clear(); for (i = 0; i < n; ++i){ a = Get(); b = Get(); c = Get(); tp.c = b; tp.w = c; vc[a].push_back(tp);//分类 } for (i = 1; i <= m; ++i){ for (j = 0; j <= V; ++j){ f[i][j] = -1; } } for (i = 0; i <= V; ++i) f[0][i] = 0;//初始化 for (i = 1; i <= m; ++i){ int c,w; int len = vc[i].size(); for (j = 0; j < len; ++j){ c = vc[i][j].c; w = vc[i][j].w; for (k = V; k >= c; --k){ if (f[i][k - c] != -1)//必须先计算多选的情况 f[i][k] = max(f[i][k],f[i][k - c] + w); if (f[i - 1][k - c] != -1) f[i][k] = max(f[i][k],f[i - 1][k - c] + w); } } } if (f[m][V] == -1) puts("Impossible"); else printf("%d\n",f[m][V]); } return 0; }
待更新......