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;
}
标签:LG4026,数为,题解,ll,钞票,SHOI2008,include,分配,dp
From: https://www.cnblogs.com/BigSmall-En/p/16857839.html