qwertyxk | 1276 | Accepted | 584K | 47MS | C++ | 945B | 2013-01-15 14:01:27 |
这很明显是一个多重背包问题,直接套用背包九讲里面的思想来弄
最初用最简单朴素的方法来写,状态方程为:
f[i][v]=max{f[i-1][v-k*c[i]]+k*c[i] | 0<=k<=num[i]}
这个解释为,第i种物品放进去有num[i]+1种选择,取0件,1件,。。。,取num[i]件
而f[i][v]则表示前i种物品放进容量为v的背包的最大权值
于是写出了这样一个代码:
#include<stdio.h>
#include<string.h>
int num[1005],c[1005],dp[15][100005];
int main()
{
int cash,n,i,j,k,max;
while(scanf("%d%d",&cash,&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d%d",num+i,c+i);
if(cash==0||n==0)
printf("0\n");
else
{
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
for(j=cash;j>=0;j--)
{
max=0;
for(k=0;k<=num[i];k++)
{
if(j-k*c[i]>=0)
{
if(dp[i-1][j-k*c[i]]+k*c[i]>max)
max=dp[i-1][j-k*c[i]]+k*c[i];
}
}
dp[i][j]=max;
}
printf("%d\n",dp[n][cash]);
}
}
return 0;
}
经测试一些用例,并没有错误,但是提交上去显示TLE
可以知道这种简单的方法时间复杂度太高,导致超时了,粗略一看 ,时间复杂度为O(n*cash*每一样物品的件数)
由于cash可以达到十万数量级,所以这样一个立方级别的时间复杂度肯定会超时
立即改程序,用背包九讲里面的思想:将多重背包转变成01背包和完全背包的思想来改进程序
里面的说法是可以将复杂度改变为O(n*cash*log(每一样物品的件数))
于是将程序改进,再提交AC ,具体详见下面的代码:
#include<stdio.h>
#include<string.h>
int dp[100005],c[1005],num[1005],cash;
int max(int a,int b)
{
return a>b?a:b;
}
void zeroonepack(int cost,int weight) //01背包处理
{
for(int v=cash;v>=cost;v--)
dp[v]=max(dp[v],dp[v-cost]+weight);
}
void completepack(int cost,int weight) //完全背包处理
{
for(int v=cost;v<=cash;v++)
dp[v]=max(dp[v],dp[v-cost]+weight);
}
void multiplepack(int cost,int weight,int amount)
{
if(cost*amount>=cash)
completepack(cost,weight);
else
{
int k=1;
while(k<amount)
{
zeroonepack(k*cost,k*weight);
amount-=k;
k*=2;
}
zeroonepack(amount*cost,amount*weight);
}
}
int main()
{
int n,i;
while(scanf("%d%d",&cash,&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d%d",num+i,c+i);
if(cash==0||n==0)
printf("0\n");
else
{
for(i=0;i<=cash;i++)
dp[i]=0;
for(i=1;i<=n;i++)
multiplepack(c[i],c[i],num[i]);
printf("%d\n", dp[cash]);
}
}
return 0;
}
关于背包九讲的思想,详见:http://wenku.baidu.com/view/8b3c0d778e9951e79b892755.html
感谢作者的无私奉献