[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 }
View Code

 

posted @ 2017-10-14 11:19  wls001  阅读(157)  评论(0编辑  收藏  举报