一道背包问题 BunOJ 29376 沙漠之旅
来源:互联网 发布:js在线解密工具 编辑:程序博客网 时间:2024/04/24 19:04
来源:第十一届北京师范大学程序设计竞赛决赛
题意:给定一个容量L, N个物品的重量W[i],每种物品有无限个,求是否能够总共用4个物品恰好填满容量L。1<=L<=1000,1<=w[i]<=1000
思路:
第一种:考虑到只选4个出来,我们可以分情况讨论:
(1).用了4种物品,即每种物品一个 (1 1 1 1)
(2).用了3种物品,(1 1 2)
(3).用了2种物品,(2 2) (1 3)
(4).用了1种物品,(4)
判断4种情况是否有成立的,有一种符合要求即可。
第二种:背包DP
设f[i][j]表示容量为i时,已经装了j个物品的状态是否成立,等于1成立,等于0不成立。
For(int i=1;i<=n;i++)
For(int k=1;k<=4;k++)
For(int j=l;j>=a[i];j--)
f[j][k]=f[j][k] | f[j-a[i]][k-1];
第三种:考虑到总共4个物品
我们先for(int i=1;i<=n;i++)
For(int j=1;j<=n;j++)
if(a[i]+a[j]<=l)exist[a[i]+a[j]]=1;
预处理出任意两个物品可以达到的容量(物品可以是一个种类,也可以是两种).
然后枚举两个物品可以达到的容量,并判断剩下还需填充的是否也是任意两个物品的容量。
For(int i=0;i<=l;i++)
If(exist[i] && exist[l-i]) Yes;
这种方法相比于直接枚举4个物品,非常巧妙的降低了时间复杂度。
这里有一种对称和分治(二分)的思想。那比如我需要判断8个物品的情况,就先预处理出4个物品的情况,而4个物品的情况又由2的物品的情况预处理得来。
当然此题背包DP的解法是一定要掌握的。
附上三种解法代码:
//解法一
#include<cstdio>#include<iostream>#include<cstring>#include<string>using namespace std;int a[1100];bool exist[1100];int f[1100][1100][5];int n,m;bool work(){//用了三种油 (1 1 2)if(n>=3){for(int i=0;i<n;i++)for(int j=0;j<n;j++){int xx=a[i]*2+a[j];if(xx<m)if(exist[m-xx])return 1;}}//用了两种油 (2 2) (3 1)if(n>=2)for(int i=0;i<n;i++)for(int j=0;j<n;j++){int xx=a[i]*2+a[j]*2;if(xx==m)return 1;xx=a[i]*3+a[j];if(xx==m)return 1;}//用了一种油 (4)for(int i=0;i<n;i++)if(a[i]*4==m)return 1;//用了四种油 (1 1 1 1) if(n>=4) { memset(f,0,sizeof(f)); f[0][0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=4;k++) { f[i][j][k]=f[i-1][j][k]; if(k>=1 && j-a[i-1]>=0)f[i][j][k]=f[i][j][k] | f[i-1][j-a[i-1]][k-1]; } if(f[n][m][4])return 1; }return 0;}int main(){int T,l,x;scanf("%d",&T);while(T--){scanf("%d%d%d",&l,&x,&n);memset(exist,0,sizeof(exist)); m=l-x;for(int i=0;i<n;i++){scanf("%d",&a[i]);exist[a[i]]=1;}bool flag=work();if(flag)printf("Yes\n");else printf("No\n");}return 0;}
//解法二
#include<cstdio>#include<iostream>#include<string>#include<cstring>using namespace std;int f[1110][5];int a[1010];int main(){int T;scanf("%d",&T);while(T--){int l,x,n;scanf("%d%d%d",&l,&x,&n);l-=x;for(int i=1;i<=n;i++)scanf("%d",&a[i]);memset(f,0,sizeof(f));f[0][0]=1;for(int i=1;i<=n;i++)for(int k=1;k<=4;k++)for(int j=l;j>=a[i];j--){f[j][k]=f[j-a[i]][k-1]|f[j][k];}if(f[l][4])printf("Yes\n");else printf("No\n");}return 0;}
//解法三
#include<cstdio>#include<iostream>#include<cstring>using namespace std;bool exist[1010];int a[1010];int main(){int T;scanf("%d",&T);while(T--){int l,x,n;scanf("%d%d%d",&l,&x,&n);l-=x;for(int i=1;i<=n;i++)scanf("%d",&a[i]);memset(exist,0,sizeof(exist));bool flag=0;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[i]+a[j]<=l)exist[a[i]+a[j]]=1;for(int i=0;i<=l;i++)if(exist[i]&&exist[l-i]){flag=1;break;}flag?puts("Yes"):puts("No");}return 0;}
- 一道背包问题 BunOJ 29376 沙漠之旅
- bnu 沙漠之旅 (二维背包)
- B. 沙漠之旅(分组背包)
- BNUOJ--29376 沙漠之旅
- BNU 沙漠之旅
- BNUOJ29376 沙漠之旅
- 沙漠之旅
- BNU 沙漠之旅
- 沙漠之旅 && 抽签
- HihoCoder]#1375 : 沙漠之旅
- 沙漠之旅(二维dp)
- BNUOJ 29376 沙漠之旅 // 第十一届北京师范大学程序设计竞赛决赛
- 1076穿越沙漠问题
- 穿越沙漠问题
- 穿越沙漠的问题
- 卡车穿越沙漠问题
- 穿越沙漠问题
- 过沙漠的问题
- 我没有博客,我要有博客
- windows phone 8中使用蓝牙
- 惹端费行巫阶宋誓胀鹤锰
- 黑马程序员_学习笔记第20天——Object流、管道流、数据流
- Android 内核下载
- 一道背包问题 BunOJ 29376 沙漠之旅
- SQL性能优化工具TKPROF
- 2014-04-19编程之美初赛题目及答案解析
- [题解] 神奇的数列 -- 编程之美初赛第二场第一题
- Eclipse搭建C++开发环境报错Launch failed.Binary not found
- 指向多维数组的指针变量
- java中解决从JSP页面获取中文乱码的问题
- qt基础
- 常见C++内存池技术