博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2019 ICPC Malaysia National,E. Optimal Slots(01背包变形)
阅读量:4048 次
发布时间:2019-05-25

本文共 1916 字,大约阅读时间需要 6 分钟。

大致题意:给定T和N个数,在N个数当中选出一些数相加,得到sum,你的任务就是要使sum<=T且T-sum要尽可能小,最后按照编号顺序输出你的方案,最后再输出sum。如果有多个方案,编号小的优先。

限制条件:1<=N<=50, 1<=T<=1000.
这道题很坑的地方就是题中是没有给出T的范围的(本人是在CF上做的,至少在CF上是没有的),只给出N的范围。所以刚开始看到这道题是考虑用折半搜索,然而实现的方法不对导致超时。之后偶然发现T的范围后才改用01背包去做。

如果用01背包做的话,那么原题就转化为了,给定一个容量T的背包,有N个物品,每个物品都有一个体积,你的任务就是从这N个物品中挑出一些物品尽可能的填满这个背包。最后输出你的挑选方案。

设sum为挑出来的这些物品的体积之和,sum还是很容易就求出来的,关键是挑选方案。那么我们考虑回溯?因为DP也是可以用回溯找出方案的?可以,不过可能会很麻烦,不得已不建议。那要咋办?观察一下N的大小,N最大为50,250是在long long以内的,既然如此,我们就可以用一个二进制数来表示这个方案。举个例子:

Input: 5 5 1 2 3 4 5
output: 1 4 5
那么选1,4的方案就可以表示为(10010)=18。
但是题意是要求如果有多个方案,要输出编号小的,例如上述例子也可以选2,3,但最终是输出1,4。这个要如何判断?
选择1,4的方案为(10010)=18,选择2,3的方案为(01100)=12,可以发现18>12。实际上,假设方案1用二进制数表示为k1,方案2用二进制数表示为k2,如果k1>k2,我们就选k1,否则选k2(可以自行多写几个样例验证一下)。

代码如下:

#include
#include
#include
#include
using namespace std;typedef long long ll;const int maxn=1e3+5;int n,T;ll a[55];struct node{ bool flag; //dp[i][j].flag表示前i种物品能否填满容量为j的背包 ll sum; //dp[i][j[.sum表示前i中物品填满容量为j的背包的方案}dp[55][maxn]; int main(){ while(~scanf("%d",&T)) { if(!T) break; scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lld",&a[i]); for(int i=0;i<=n;++i) for(int j=0;j<=T;j++) dp[i][j].flag=dp[i][j].sum=0; for(int i=0;i<=n;++i) dp[i][0].flag=1; for(int i=1;i<=n;++i) { for(int j=1;j<=T;++j) { dp[i][j]=dp[i-1][j]; //这一步别忘了 if(j>=a[i]) { if(dp[i-1][j-a[i]].flag) { if(!dp[i][j].sum) { dp[i][j].flag=1; dp[i][j].sum=dp[i-1][j-a[i]].sum+(1ll<<(n-i)); //额...一开始1没有加llWA了1次,记得加 } else if(dp[i-1][j-a[i]].sum+(1ll<<(n-i))>dp[i][j].sum) //>就行,是不会=的 { dp[i][j].flag=1; dp[i][j].sum=dp[i-1][j-a[i]].sum+(1ll<<(n-i)); } } } } } int ans=0;ll sum=0; for(int i=T;i>=1;i--) if(dp[n][i].flag) { ans=i; sum=dp[n][i].sum; break; } for(int i=n;i>=1;--i) { if(1ll&(sum>>(i-1))) printf("%d ",a[n-i+1]); } printf("%d\n",ans); } return 0;}

转载地址:http://twdci.baihongyu.com/

你可能感兴趣的文章
关于字符串逆序的问题
查看>>
嵌入式及手机开发[笔试题目]
查看>>
Sony Ericsson Z610i
查看>>
MTK的暗码
查看>>
LCD的接口分类
查看>>
LCD点屏心得
查看>>
可重入函数
查看>>
C语言嵌入式系统编程修炼之道
查看>>
linux内核驱动开发笔试题
查看>>
XX公司招聘C笔试题
查看>>
×××公司linux内核驱动开发招聘笔试题
查看>>
驱动版Hello World
查看>>
sizeof,终极无惑(上)
查看>>
常考--宏与内联函数
查看>>
C语言面试题大汇总
查看>>
C/C++ 笔试、面试题目大汇总
查看>>
One Of My True Dreams
查看>>
我看无损音频APE和FLAC
查看>>
dBm, dBi, dBd, dB, dBc 详解
查看>>
堆(heap)和栈(stack)的区别
查看>>