人,只有自己站起来,这个世界才能属于他。|

园龄:粉丝:关注:

题解:P4026 [SHOI2008] 循环的债务

前言

需要脑子题。

思路分析

首先受到样例二的启发,如果我们决策这个交换纸币的过程也太困难了。所以需要换一种刻画方式。

考虑把所有纸币都放在桌子上,三个人再分配。代价就是分配之前和分配之后,每种面值的纸币的差。

这样就好 DP 了。

fi,a,b 表示前 i 中面值的纸币,第一个人有 a 元,第二个人有 b 元。第三个人有多少钱可以计算出来。

每次转移时,枚举第一个人拿几张,第二个人拿几张,第三个人拿几张,背包一下就行。

复杂度不高,不想精细计算了。

代码实现

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int x1,x2,x3,a[7],b[4][7],f[7][1001][1001],tot[7],num[7],sum[7],ans;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>x1>>x2>>x3;
	a[1]=100,a[2]=50,a[3]=20,a[4]=10,a[5]=5,a[6]=1;
	for(int i=1;i<=3;i++){
		for(int j=1;j<=6;j++){
			cin>>b[i][j];
			sum[i]+=b[i][j]*a[j];
			tot[j]+=b[i][j]*a[j];
			num[j]+=b[i][j];
		}
	}
	for(int i=1;i<=6;i++){
		tot[i]+=tot[i-1];
	}
	sum[1]+=x3-x1;
	sum[2]+=x1-x2;
	sum[3]+=x2-x3;
	if(sum[1]<0 || sum[2]<0 || sum[3]<0){
		cout<<"impossible";
		return 0;
	}
	memset(f,0x3f,sizeof(f));
	f[0][0][0]=0;
	for(int i=1;i<=6;i++){
		for(int a1=0;a1<=sum[1] && a1<=tot[i];a1++){
			for(int a2=0;a2<=sum[2] && a2<=tot[i] && a1+a2<=tot[i];a2++){
				int a3=tot[i]-a1-a2;
				if(a3<0 || a3>sum[3]) continue;
				for(int l1=0;l1<=num[i] && l1*a[i]<=a1;l1++){
					for(int l2=0;l2<=num[i] && l1+l2<=num[i] && l2*a[i]<=a2;l2++){
						int l3=num[i]-l1-l2;
						if(l3<0 && a3<l3*a[i]) continue;
						f[i][a1][a2]=min(f[i][a1][a2],f[i-1][a1-l1*a[i]][a2-l2*a[i]]+(abs(l1-b[1][i])+abs(l2-b[2][i])+abs(l3-b[3][i]))/2);
					}
				}
			}
		}
	}
	ans=f[6][sum[1]][sum[2]];
	if(ans>inf) cout<<"impossible";
	else cout<<ans;
	return 0;
}

本文作者:Kenma

本文链接:https://www.cnblogs.com/Kenma/p/18691166

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起