Coins

HDOJ的这道题比较水,POJ的题好牛

N - Coins

Time Limit:1000MS     MemoryLimit:32768KB     64bit IO Format:%I64d& %I64u

Submit Status

Description

Whuacmers usecoins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibixopened purse and found there were some coins. He decided to buy a very nicewatch in a nearby shop. He wanted to pay the exact price(without change) and heknown the price would not more than m.But he didn't know the exact price of thewatch. 

You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cncorresponding to the number of Tony's coins of value A1,A2,A3...An thencalculate how many prices(form 1 to m) Tony can pay use these coins.

 

Input

The inputcontains several test cases. The first line of each test case contains twointegers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers,denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The lasttest case is followed by two zeros.

 

Output

For each testcase output the answer on a single line.

 

Sample Input

3 10

1 2 4 2 1 1

2 5

1 4 2 1

0 0

 

Sample Output

8

4

 

 

 

HDOJ版:

 

一开始根本想不到优化,之后上网搜题解发现什么二进制优化,学习了。之后就是将多重背包转化为完全或01背包。代码如下:


#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int T = 0x3f3f3f3f;
struct S
{
	int val,sum;
};
int dp[100001];
void INIT(int k)
{
	for(int i=0;i<=k;++i)
	{
		dp[i]=T;
	}
	dp[0]=0;
}
int main()
{
	S a[110];
	int n,m,i,j,k;
	
	while(scanf("%d%d",&n,&m)&&(n&&m))
	{
		INIT(m);
		for(i=0;i<n;++i)
		{
			scanf("%d",&a[i].val);
		}
		for(i=0;i<n;++i)
		{
			scanf("%d",&a[i].sum);
		}
		for(i=0;i<n;++i)
		{
			if(a[i].val*a[i].sum>=m)
			{
				for(j=a[i].val;j<=m;++j)
				{
					dp[j]=min(dp[j],dp[j-a[i].val]+1);
				}
			}
			else
			{
				k=1;
				while(k<a[i].sum)
				{
					for(j=m;j>=k*a[i].val;--j)
					{
						dp[j]=min(dp[j],dp[j-k*a[i].val]+1);
					}
					a[i].sum-=k;//每进行一次就就要改变数量方便知道是否用完
					k*=2;
				}
				if(a[i].sum)
				{
					for(j=m;j>=a[i].sum*a[i].val;--j)
					{
						dp[j]=min(dp[j],dp[j-a[i].sum*a[i].val]+1);
					}
				}
			}
		}
		for(i=1,k=0;i<=m;++i)
		{
			if(dp[i]!=T)
			{
				k++;
			}
		}
		printf("%d\n",k);
	}
	return 0;
}

POJ版:

这题消掉第三个循环挺难想到的,如果没看别人的题解根本想不出要怎麽做。其实就是利用一个cnt数组将用了多少个物品的个数记录下来,而物品的使用又与动态转移时的前一个状态dp[i-1][j-a[i]。val]有关,所以cnt的使用次数也是这个状态的转移方程。即是这个题目一共使用了两个状态转移方程,一个是dp价值,一个是cnt次数,他们是紧密联系在一起的。只能一起转移或都不转移两种。

 

#include<iostream>
#include<algorithm>	
#include<cstring>
#include<cstdio>
using namespace std;
const int T = 0x3f3f3f3f;
int dp[100100],cnt[100100];
void INIT(int m)
{
	for(int i=0;i<=m;++i)
	{
		dp[i]=T;
	}
	dp[0]=0;
}
struct S
{
	int val,sum;
}a[110];
int main()
{
	int n,m,i,j,k;
	while(scanf("%d%d",&n,&m)&&(m+n))
	{
		INIT(m);
		for(i=0;i<n;++i)
		{
			scanf("%d",&a[i].val);
		}
		for(i=0;i<n;++i)
		{
			scanf("%d",&a[i].sum);
		}
		for(i=0,k=0;i<n;++i)
		{
			memset(cnt,0,sizeof(cnt));
			for(j=a[i].val;j<=m;++j)
			{
				if(dp[j]==T&&!dp[j-a[i].val]&&cnt[j-a[i].val]<a[i].sum)
			/* 
			    dp[j]=未组合的数dp[j-a[i]。val]=组合了的数
			    cnt[j-a[i].val]=当前组合用了多少个个数
			*/
				{
					dp[j]=0;
					cnt[j]=cnt[j-a[i].val]+1;
					k++;//符合条件的加一
				}
			}
		}
		printf("%d\n",k);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值