POJ 3093 Margaritas on the River Walk

来源:互联网 发布:淘宝修改中差评 编辑:程序博客网 时间:2024/05/01 18:14

给n个物品,容量为V的包,要求这样的方案数:选中k个物品放入背包后,剩下的物品中,任意一个都放不进去

考虑什么情况下一个都放不进去,就是剩下物品中体积最小的那个(体积为v)都放不进去,即背包装载容量应为[V-v+1,V]

那么我们可以将物品按容量排序,从小到大枚举不放入背包的体积最小的,那么此时比它小的物品都应该放入背包中,我们可以对剩下的i+1到n的物品做01背包,然后将可行的方案统计出来,这样,第i件物品考虑了i-1次,总复杂度为O(n^2*V)

n较大的话会超时,我们可以反过来做,每个物品只放入背包中一次,即枚举的时候从最大的开始,先统计此时的方案数,然后将物品放入背包,这样一直下去,总复杂度O(n*V)

具体可以参见《浅谈几类背包问题》

代码1:

#include<iostream>#include<memory.h>#include<string>#include<cstdio>#include<algorithm>#include<math.h>#include<stack>#include<queue>#include<vector>#include<map>using namespace std;int dp[1005],sum[35],w[35];int main(){int i,j,k,T,n,V,ans,ca;scanf("%d",&T);for(ca=1;ca<=T;ca++){scanf("%d%d",&n,&V);for(i=1;i<=n;i++){scanf("%d",&w[i]);}sort(w+1,w+1+n);sum[0]=0;for(i=1;i<=n;i++)sum[i]=sum[i-1]+w[i];ans=0;for(i=1;i<=n;i++){memset(dp,0,sizeof(dp));dp[0]=1;for(j=i+1;j<=n;j++){for(k=V-sum[i-1];k>=w[j];k--){if(dp[k-w[j]]!=0)dp[k]+=dp[k-w[j]];}}for(j=max(0,V-sum[i-1]-w[i]+1);j<=V-sum[i-1];j++){ans+=dp[j];}}if(w[1]>V)ans=0;printf("%d %d\n",ca,ans);}return 0;}

代码2:

#include<iostream>#include<memory.h>#include<string>#include<cstdio>#include<algorithm>#include<math.h>#include<stack>#include<queue>#include<vector>#include<map>using namespace std;int dp[1005],sum[35],w[35];int main(){int i,j,k,T,n,V,ans,ca;scanf("%d",&T);for(ca=1;ca<=T;ca++){scanf("%d%d",&n,&V);for(i=1;i<=n;i++){scanf("%d",&w[i]);}sort(w+1,w+1+n);sum[0]=0;for(i=1;i<=n;i++)sum[i]=sum[i-1]+w[i];ans=0;memset(dp,0,sizeof(dp));dp[0]=1;for(i=n;i>=1;i--){k=max(0,V-sum[i-1]-w[i]+1);for(j=V-sum[i-1];j>=k;j--)ans+=dp[j];for(j=V;j>=w[i];j--)dp[j]+=dp[j-w[i]];}if(w[1]>V)ans=0;printf("%d %d\n",ca,ans);}return 0;}

原创粉丝点击