背包习题
来源:互联网 发布:程序员加薪申请书范文 编辑:程序博客网 时间:2024/05/20 11:52
【题目大意】6种价值分别为1 2 3 4 5 6的石头,给出每种石头的数目,问能不能将这些石头分为价值相等的两堆。
【解析】经典的多重背包问题,a[]数组即为1 2 3 4 5 6,count数组题目给出,怎么做呢?上面提到一点,设dp[i]表示容量为i的背包能不能被所给物体装满。如果dp[sum/2]==1,那么就说明可以分为两堆(sum是所有石头的总价值),直接套用上面的模板即可。
#include <cstdio>#include <cstring>using namespace std;int a[10];int dp[120100];int main(){ int cas = 0; while( ++ cas ){ int sum = 0; for(int i = 1; i <= 6; ++i){ scanf("%d",&a[i]); sum += a[i]*i; } if(sum == 0)break; memset(dp,0,sizeof(dp)); printf("Collection #%d:\n",cas); if(sum % 2 == 1){ puts("Can't be divided."); puts(""); continue; } dp[0] = 1; //O(NV)的方法 int dpt[120000]; for(int i = 1; i <= 6; ++i){ memset(dpt,0,sizeof(dpt)); for(int j = i; j <= sum/2; ++j){ if (!dp[j] && dp[j-i]&& dpt[j-i] < a[i]) { dpt[j] = dpt[j-i] + 1; dp[j] = 1; } } } /* //二进制优化的方法 for(int i = 1;i <= 6;++i){ int k; for(k = 1;k*2 < a[i]+1;k *= 2) for(int v = sum/2;v >= k*i;--v) if(dp[v-k*i]) dp[v]=true; k = a[i]+1-k; for(int v = sum/2;v > k*i;--v) if([v-k*i]) dp[v] = true; } */ if(dp[sum/2]){ puts("Can be divided."); } else {puts("Can't be divided.");}; puts(""); } return 0;}
【题目大意】给若干组物品,每组物品都有一个箱子(箱子自身也有cost),然后就是物品的cost和value,要买某个物品必须也要买装这个物品的箱子,给一定钱数,问能获得的最大价值。
【题目解析】可以参照背包九讲第六讲和第七讲里的内容解决该问题(相当对口,这题就是根据背包九讲来的)
有一种比较简单的写法,两次背包即可。
#include<iostream>using namespace std;const int MAXN = 100000;int main(){ int n,total,boxcost,goodnum,cost,value,i,j,t; int dpbox[MAXN],dptotal[MAXN]; while(scanf("%d%d",&n,&total) != EOF) { memset(dptotal,0,sizeof(dptotal)); for(i = 0; i < n; i++) { scanf("%d%d",&boxcost,&goodnum); memcpy(dpbox,dptotal,sizeof(dptotal)); for(j = 0; j < goodnum; j++) { scanf("%d%d",&cost,&value); for(t = total - boxcost; t >= cost; t--) { if(dpbox[t] < dpbox[t - cost] + value) dpbox[t] = dpbox[t-cost] + value; } } for(t = total; t >= boxcost; t--) if(dptotal[t] < dpbox[t-boxcost]) dptotal[t] = dpbox[t-boxcost]; } printf("%d\n",dptotal[total]); } return 0;}
【题目大意】一个人有T分钟去做工作,共有n组工作,每一组有若干工作,每个工作消耗的时间和得到的快乐值已知,每一个组有一个标识位,标识位为0,则该组中至少应该选取一样工作完成,标识位为1,则该组中至多有一个工作被选择,标识位为2,无限制。
【分析】对标识位为2的工作组,因为无限制条件,每个工作可做可不做,即用简单的01背包即可处理。对标识位为1的工作组,因为至多选择一个工作,所以本次操作只对dp数组选取最优值更新一次即可。对至少选择一个的工作组,还不是太理解,只是看别人代码写的,还请大家集思广益,有想法可以留言评论,以后理解透彻了以后会做补充。
#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <vector>#include <map>using namespace std;const int maxt = 100 + 10;int dp[maxt];int td[maxt], n, m, t;void dp0() { //至少取一个 memcpy (td, dp, sizeof(td)); memset (dp, -1, sizeof(dp)); for (int i = 0, a, b; i < m; ++i) { scanf ("%d%d", &a, &b); for (int j = t; j >= a; --j) {//注意怎样保证至少取一个?? if (dp[j-a] != -1) { dp[j] = max(dp[j], dp[j-a] + b); } if (td[j-a] != -1) { dp[j] = max(dp[j], td[j-a] + b); } } }}void dp1() { //最多取一个,用上次得到的dp值更新最优值,只更新一次 memcpy(td, dp, sizeof(td)); for (int i = 0, a, b; i < m; ++i) { scanf ("%d%d", &a, &b); for (int j = t; j >= a; --j) { if (td[j-a] != -1) { dp[j] = max(dp[j], td[j-a] + b); } } }}void dp2() { //无条件限制,01背包,更新多次 for (int i = 0, a, b; i < m; ++i) { scanf ("%d%d", &a, &b); for (int j = t; j >= a; --j) { if (dp[j-a] != -1) { dp[j] = max(dp[j], dp[j-a] + b); } } }}void init() { memset (dp, -1, sizeof(dp)); dp[0] = 0; for (int i = 0, s; i < n; ++i) { scanf ("%d%d", &m, &s); if (s == 0) dp0(); else if (s == 1) dp1(); else if (s == 2) dp2(); }}void solve() { int ans = -1; for (int i = 0; i <= t; ++i) ans = max(ans, dp[i]); printf ("%d\n", ans);}int main() { //freopen("ar.txt","r",stdin); while (scanf ("%d%d", &n, &t) != EOF) { init(); solve(); } return 0;}
- 背包习题
- 背包习题总结
- 动态规划--背包问题,带习题
- UVA242 背包问题&紫书dp习题9-5
- 动态规划(1)0-1背包同类型习题
- 背包问题小总结 习题(动态规划01背包(第k优解)完全背包,多重背包)acm杭电HDU2639,HDU2602,HDU1114,HDU2191
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- 习题
- POJ2002 Squares(hash)
- pdf加书签
- 对JS对象的理解
- android中 代码实现截图功能(静态+动态视频)
- 三、文件操作 1、文件的创建和读写
- 背包习题
- Comparing Struts 1 and 2
- Android实现左右滑动指引效果
- 黑马程序员-线程
- 将CString转化为char*
- hibernate根据条件动态组装sql/hql语句(仿ibatis动态查询语句功
- 黑马程序员-网络编程
- 页面加载JS两种方式
- union和struct的区别