【贪心】Allowance POJ 3040

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ike940067893/article/details/75170561

题目链接:http://poj.org/problem?id=3040

题目大意:你有n种不同面值的硬币,面值为vi的有bi个。“硬币的面额均匀地分配下一个更大的面额”,即下一个更大的硬币面值是此面值的倍数。你一周需要支付至少c元,没有退钱,每次只能给一周的钱。问最多能支撑几周。

首先对于面值大于c的硬币每个支撑一周。然后从大到小填充c直到填不下或刚好满,如果刚好满就打个标记、ans++。否则从小到大填充直到填满或大于。这里有一个优化,就是每次你配对出来一个方案,可以保存每种用了多少,然后把这些组成一个套装(k为最大目前可用套数),来支撑k个周。

贴代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
	int v,b;
	friend bool operator <(node x,node y){
		return x.v<y.v;
	}
}a[25];
int use[25];
int main()  
{
	int n,c,ans=0;
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].v,&a[i].b);
	sort(a+1,a+n+1);
	for(int i=n;i>=1;i--)
	{
		if(a[i].v<c) break;
		ans+=a[i].b;a[i].b=0;
	}
	while(1)
	{
		bool flag=0;int tmp=c;
		memset(use,0,sizeof use);
		for(int i=n;i>=1;i--)
		{
			if(a[i].b==0)continue;
			use[i]=tmp/a[i].v;
			tmp-=min(use[i],a[i].b)*a[i].v;
			a[i].b-=min(use[i],a[i].b);
			if(tmp==0){
				ans++;flag=1;break;
			}
		}
		if(!flag)
		{
			for(int i=1;i<=n;i++)
			{
				if(a[i].b==0)continue;
				tmp-=a[i].v;a[i].b--;use[i]++;
				if(tmp<0){
					ans++;flag=1;break;
				}
			}
		}
		if(!flag)break;
		int k=100000000,mn;
		for(int i=1;i<=n;i++)
			if(use[i]){
				mn=a[i].b/use[i];
				k=min(k,mn);
			}
		for(int i=1;i<=n;i++)
			if(use[i])
				a[i].b-=k*use[i];
		ans+=k;
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/75170561