Gushing over Pro|

BigSmall_En

园龄:3年2个月粉丝:3关注:5

2022-11-04 15:03阅读: 29评论: 0推荐: 0

LG4026 [SHOI2008]循环的债务 题解

LG4026 [SHOI2008]循环的债务

给出三个整数 \(x_1,x_2,x_3\)

\(x_1\) 代表 A 欠 B 的钱数,\(x_2\) 表示 B 欠 C 的钱数,\(x_3\) 表示 C 欠 A 的钱数。

接下来 \(3\) 行,每行包括 \(6\) 个自然数,为

\[\begin{array}{llllll} a_{1} & a_{2} & a_{3} & a_{4} & a_{5} & a_{6} \\ b_{1} & b_{2} & b_{3} & b_{4} & b_{5} & b_{6} \\ c_{1} & c_{2} & c_{3} & c_{4} & c_{5} & c_{6} \end{array} \]

分别表示 A,B,C 三人所拥有的 \(v=\{100,50,20,10,5,1\}\) 元钞票数。

问如果三人的债务可以还清,输出需要交换钞票的最少张数,否则输出 \(\texttt{impossible}\)

A 目前拥有的钱数为 \(suma=100a_{100}+50a_{50}+20a_{20}+10a_{10}+5a_5+a_1\),B,C 计算同理。

A 还债后的钱数为 \(suma-x_1+x_3\),B 还债后的钱数为 \(sumb-x_2+x_1\),C 还债后的钱数为 \(sumc-x_3+x_2\)

我们的问题其实可以转化为了为三人分配各种钞票,使得每人每种钞票的分配数量减去原先拥有情况的绝对值之和最小。

定义每种钞票总数为 \(all_i=a_i+b_i+c_i\),设 \(dp_{i,j,k}\) 为考虑前 \(i\) 种钞票,A 已经分配 \(j\) 元,B 分配 \(k\) 元,此时与原先分配情况差的绝对值。假设 A 分配 \(x\) 张此种钞票,B 分配 \(y\) 张此种钞票,则 C 分配到 \(all_i-x-y\) 张。得到转移

\[dp_{i,j,k}\gets dp_{i-1,j-x\times v_i,k-y\times v_i}+|x-a_i|+|y-b_i|+|all_i-x-y-c_i| \]

具体细节见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
	while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=1003,INF=0x3f3f3f3f;
const int val[7]={0,100,50,20,10,5,1};
int a[7],b[7],c[7],all[7];
int va,vb,vc,suma,sumb,sumc,ha,hb,hc,sum;
int dp[7][N][N];
int main(){
	va=read(),vb=read(),vc=read();
	for(int i=1;i<=6;++i){
		a[i]=read();
		suma+=a[i]*val[i];
	}
	for(int i=1;i<=6;++i){
		b[i]=read();
		sumb+=b[i]*val[i];
	}
	for(int i=1;i<=6;++i){
		c[i]=read();
		sumc+=c[i]*val[i];
	}
	sum=suma+sumb+sumc;
	for(int i=1;i<=6;++i)all[i]=a[i]+b[i]+c[i];
	ha=suma+vc-va,hb=sumb+va-vb,hc=sumc+vb-vc;
	//("%d %d %d\n",ha,hb,hc);
	memset(dp,0x3f,sizeof(dp));
	dp[0][0][0]=0;
	for(int i=1;i<=6;++i){
		for(int j=ha;j>=0;--j){
			for(int k=hb;k>=0;--k){
				if(j+k>sum)continue;
				for(int v1=0;v1<=all[i]&&v1*val[i]<=j;++v1){
					for(int v2=0;v1+v2<=all[i]&&v2*val[i]<=k;++v2){
						dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-v1*val[i]][k-v2*val[i]]+abs(v1-a[i])+abs(v2-b[i])+abs(all[i]-v1-v2-c[i]));
					}
				}
			}
		}
	}
	if(dp[6][ha][hb]<INF)printf("%d\n",dp[6][ha][hb]/2);
	else puts("impossible");
	return 0;
}

本文作者:BigSmall_En

本文链接:https://www.cnblogs.com/BigSmall-En/p/16857839.html

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

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