[BZOJ1021][SHOI2008]Debt 循环的债务
1021: [SHOI2008]Debt 循环的债务
Time Limit: 1 Sec Memory Limit: 162 MB Submit: 1092 Solved: 558 [Submit][Status][Discuss]Description
Alice、Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题。 不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的时候尽可能少的交换现金。比如说,Al ice欠Bob 10元,而Cynthia和他俩互不相欠。现在假设Alice只有一张50元,Bob有3张10元和10张1元,Cynthia有3 张20元。一种比较直接的做法是:Alice将50元交给Bob,而Bob将他身上的钱找给Alice,这样一共就会有14张钞票 被交换。但这不是最好的做法,最好的做法是:Alice把50块给Cynthia,Cynthia再把两张20给Alice,另一张20给 Bob,而Bob把一张10块给C,此时只有5张钞票被交换过。没过多久他们就发现这是一个很棘手的问题,于是他们找 到了精通数学的你为他们解决这个难题。
Input
输入的第一行包括三个整数:x1、x2、x3(-1,000≤x1,x2,x3≤1,000),其中 x1代表Alice欠Bob的钱(如 果x1是负数,说明Bob欠了Alice的钱) x2代表Bob欠Cynthia的钱(如果x2是负数,说明Cynthia欠了Bob的钱) x3 代表Cynthia欠Alice的钱(如果x3是负数,说明Alice欠了Cynthia的钱) 接下来有三行 每行包括6个自然数: a100,a50,a20,a10,a5,a1 b100,b50,b20,b10,b5,b1 c100,c50,c20,c10,c5,c1 a100表示Alice拥有的100元钞票张数,b50表示Bob拥有的50元钞票张数,以此类推。 另外,我们保证有a10+a5+a1≤30,b10+b5+b1≤30,c10+c5+c1≤30,而且三人总共拥有的钞票面值总额不会 超过1,000。
Output
如果债务可以还清,则输出需要交换钞票的最少张数;如果不能还清,则输出“impossible”(注意单词全部 小写,输出到文件时不要加引号)。
Sample Input
10 0 0
0 1 0 0 0 0
0 0 0 3 0 10
0 0 3 0 0 0
输入二
-10 -10 -10
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Sample Output
5
输出二
0
HINT
对于100%的数据,x1、x2、x3 ≤ |1,000|。
设f[i][j][k]表示前i个的价值,第一个人有j元,第二个人有k元的最小方案数,转移时枚举当前面值个数即可。
注意,面值从1-100枚举更快。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int p[10]={0,1,5,10,20,50,100}; 9 int sum[10],cnt[10]; 10 int c[10][10]; 11 int x1,x2,x3; 12 int f[10][1005][1005]; 13 int tot; 14 int calc(int a,int b,int i) { 15 return (abs(a-c[1][i])+abs(b-c[2][i])+abs(cnt[i]-a-b-c[3][i]))/2; 16 } 17 int main() { 18 scanf("%d%d%d",&x1,&x2,&x3); 19 for(int i=1;i<=3;i++) { 20 for(int j=6;j>=1;j--) { 21 scanf("%d",&c[i][j]); 22 cnt[j]+=c[i][j]; 23 sum[i]+=c[i][j]*p[j]; 24 } 25 tot+=sum[i]; 26 } 27 memset(f,-1,sizeof(f)); 28 f[0][sum[1]][sum[2]]=0; 29 for(int i=0;i<6;i++) { 30 for(int j=0;j<=tot;j++) { 31 for(int k=0;j+k<=tot;k++) { 32 if(f[i][j][k]>=0) { 33 f[i+1][j][k]=f[i+1][j][k]==-1?f[i][j][k]:min(f[i][j][k],f[i+1][j][k]); 34 for(int a=0;a<=cnt[i+1];a++) { 35 for(int b=0;a+b<=cnt[i+1];b++) { 36 int suma=j+(a-c[1][i+1])*p[i+1],sumb=k+(b-c[2][i+1])*p[i+1]; 37 if(suma>=0&&sumb>=0&&suma+sumb<=tot) 38 f[i+1][suma][sumb]=f[i+1][suma][sumb]==-1?f[i][j][k]+calc(a,b,i+1):min(f[i+1][suma][sumb],f[i][j][k]+calc(a,b,i+1)); 39 } 40 } 41 } 42 } 43 } 44 } 45 int a=sum[1],b=sum[2],c=sum[3]; 46 a+=x3-x1,b+=x1-x2,c+=x2-x3; 47 if(a<0||b<0||c<0||a+b+c!=tot||f[6][a][b]<0) printf("impossible\n"); 48 else printf("%d\n",f[6][a][b]); 49 }