您的位置:首页 > 其它

POJ 3093 Margaritas on the River Walk 0-1背包好题

2013-08-29 10:34 357 查看
给n个物品,容量为m的包,要求这样的方案数:选中n个物品放入背包后,剩下的物品中,任意一个都放不进去。

 

我们先将物品按容量从大到小排序。

考虑以下2种情况:

1. 考虑一种特殊情况,一个都放不进去,就是剩下物品中体积最小的那个(体积为w[1])都放不进去,这个情况就会无解,答案为0;

2. 一般情况:从小到大枚举不放入背包的体积最小的,那么此时比它小的物品都应该放入背包中,此时背包装载容量应为[m-w[u]+1,m]  (1<=u<=n)

我们可以对剩下的u+1到n的物品做01背包,然后将可行的方案统计出来,这样,第u件物品考虑了u-1次,总复杂度为O(n^2*m);

优化:

n较大的话会超时,我们可以反过来做,每个物品只放入背包中一次,即枚举的时候从最大的开始,先统计此时的方案数,然后将物品放入背包,这样一直下去,总复杂度O(n*m) 即背包装载容量应为[m-w[u]+1,m]   (1<=u<=n)

一般方法:




View Code

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n, m, ans;
int w[31], sum[31];
int dp[1003];
int main()
{
int cas, i, j, u, ca=1;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
sort(w+1,w+n+1);
printf("%d ",ca++);
if(w[1]>m){printf("0\n");continue;}
sum[0]=0;ans=0;
for(i=1;i<=n;i++)
sum[i]=sum[i-1]+w[i];
for(u=1;u<=n;u++)//枚举每个不放入背包的体积最小的
{
memset(dp,0,sizeof(dp));
dp[0]=1;
for(i=u+1;i<=n;i++)
for(j=m-sum[u-1];j>=w[i];j--)//前u个物品都放入了背包中
dp[j]+=dp[j-w[i]];
for(j=max(0,m-sum[u-1]-w[u]+1);j<=m-sum[u-1];j++)
ans+=dp[j];
}
printf("%d\n",ans);
}
return 0;
}


优化:




View Code

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int sum[35],w[35];
int dp[1005];
int n, m, ans;
int main()
{
int cas, i, j, k, ca=1;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
sort(w+1,w+1+n);
printf("%d ",ca++);
if(w[1]>m){printf("0\n");continue;}
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--)
{
for(j=max(0,m-sum[i-1]-w[i]+1);j<=m-sum[i-1];j++)
ans+=dp[j];
for(j=m;j>=w[i];j--)
dp[j]+=dp[j-w[i]];
}
printf("%d\n",ans);
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: