poj 1276 Cash Machine

qwertyxk1276Accepted584K47MSC++945B2013-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

感谢作者的无私奉献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值