题目传送门
题目大意:
三人互相交换纸币使每个人都达到最终结果,试问交换纸币的最少张数。
思考过程&具体做法:
比较明显的dp,因为一共只有6种币值,考虑枚举币值,dp[i][a][b]表示枚举到第i种纸币,a的钱数为a,b的钱数为b(c的钱数为总数-a-b)的最小交换数,转移比较简单看代码吧。(我用了滚动数组写这个dp)
代码:
#include <bits/stdc++.h>
using namespace std;
int mz[6]={ 1,5,10,20,50,100 },dp[2][1010][1010],cnt[3][6],sum[3],msum[6];
int tot,x1,x2,x3;
int main()
{
scanf("%d%d%d",&x1,&x2,&x3);
for(int i=0;i<=2;i++)
{
for(int j=5;j>=0;j--)
{
scanf("%d",&cnt[i][j]);
sum[i]+=cnt[i][j]*mz[j];
tot+=cnt[i][j]*mz[j];
msum[j]+=cnt[i][j];
}
}
memset(dp[0],-1,sizeof(dp[0]));
dp[0][sum[0]][sum[1]]=0;
for(int i=0;i<=5;i++)
{
int now=1&i;
memset(dp[now^1],-1,sizeof(dp[now^1]));
for(int j=0;j<=tot;j++)
{
for(int k=0;k+j<=tot;k++)
{
if(dp[now][j][k]>=0)
{
for(int a=0;a<=msum[i];a++)
{
for(int b=0;a+b<=msum[i];b++)
{
int suma=j+(a-cnt[0][i])*mz[i];
int sumb=k+(b-cnt[1][i])*mz[i];
if(suma>=0&&sumb>=0&&suma+sumb<=tot)
{
int cnt1=(abs(a-cnt[0][i])+abs(b-cnt[1][i])+abs(msum[i]-cnt[2][i]-a-b))/2;
if(dp[now^1][suma][sumb]==-1||dp[now^1][suma][sumb]>dp[now][j][k]+cnt1) dp[now^1][suma][sumb]=dp[now][j][k]+cnt1;
}
}
}
}
}
}
}
int lasta=sum[0]-x1+x3,lastb=sum[1]-x2+x1,lastc=sum[2]-x3+x2;
if(lasta<0||lastb<0||lastc<0||dp[6&1][lasta][lastb]<0) printf("impossible\n");
else printf("%d\n",dp[6&1][lasta][lastb]);
return 0;
}