zoukankan      html  css  js  c++  java
  • bzoj 1021[SHOI2008]Debt 循环的债务

    1021: [SHOI2008]Debt 循环的债务

    Time Limit: 1 Sec  Memory Limit: 162 MB

    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|。

    初看这题,会感觉十分混乱,因为感觉每个人的状态都是不确定的

    但是忽然我们会发现一个结论

    A 给 B k 元 , 而 B 又给 C k元的情况是不存在的。

    因为A 可以越过B直接给C, 这样次数更少

    所以其实对于每种价值,只对应了6种情况:

    A -> BC 

    B -> AC

    C -> AB

    AB -> C

    AC -> B

    BC -> A

    设 f[i][j][k] 表示处理完钱i种价值, A有 j 元, B 有 k 元的最小次数

    可以直接枚举上面6种情况进行转移

    还有一个不错的优化:

    当我们进行到第i种价值时,ABC之间的钱数只会变化后面价值gcd的倍数,我们不用全部枚举了。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define LL long long
      6 
      7 using namespace std;
      8 
      9 int f[2][1100][1100];
     10 int s[4], e[4], x[4];
     11 int num[4][6];
     12 int now = 0;
     13 int sum = 0;
     14 const int inf = 1061109567;
     15 int val[6] = {1, 5, 10, 20, 50, 100};
     16 
     17 int gcd(int a, int b)
     18 {
     19     if(b == 0) {
     20         return a;
     21     } else {
     22         return gcd(b, a % b);
     23     }
     24 }
     25 inline LL read()
     26 {
     27     LL x = 0, w = 1; char ch = 0;
     28     while(ch < '0' || ch > '9') {
     29         if(ch == '-') {
     30             w = -1;
     31         }
     32         ch = getchar();
     33     }
     34     while(ch >= '0' && ch <= '9') {
     35         x = x * 10 + ch - '0';
     36         ch = getchar();
     37     }
     38     return x * w;
     39 }
     40 
     41 
     42 void dp(int v, int va, int vb) // v 表示当前交换的钱 
     43 {
     44     for(int i = 1; i <= num[1][v]; i++) { // A 给 BC
     45         if(va - i * val[v] < 0) {
     46             break;
     47         }
     48         for(int j = 0; j <= i; j++) {
     49             if(vb + j * val[v] > 1000 || sum - va - vb + (i - j) * val[v] > 1000) {
     50                 break;
     51             }
     52             f[now ^ 1][va - i * val[v]][vb + j * val[v]] = min(f[now][va][vb] + i, f[now ^ 1][va - i * val[v]][vb + j * val[v]]);    
     53         } 
     54     }
     55     for(int i = 1; i <= num[2][v]; i++) { // B 给 AC
     56         if(vb - i * val[v] < 0) {
     57             break;
     58         }
     59         for(int j = 0; j <= i; j++) {
     60             if(va + j * val[v] > 1000 || sum - va - vb + (i - j) * val[v] > 1000) {
     61                 break;
     62             }
     63             f[now ^ 1][va + j * val[v]][vb - i * val[v]] = min(f[now][va][vb] + i,     f[now ^ 1][va + j * val[v]][vb - i * val[v]]);    
     64         } 
     65     }
     66     for(int i = 1; i <= num[3][v]; i++) { // C 给 AB
     67         if(sum - va - vb - i * val[v] < 0) {
     68             break;
     69         }
     70         for(int j = 0; j <= i; j++) {
     71             if(vb + j * val[v] > 1000 || va + (i - j) * val[v] > 1000) {
     72                 break;
     73             }
     74             f[now ^ 1][va + (i - j) * val[v]][vb + j * val[v]] = min(f[now][va][vb] + i, f[now ^ 1][va + (i - j) * val[v]][vb + j * val[v]]);    
     75         } 
     76     }
     77     for(int i = 0; i <= num[2][v]; i++) { // BC 给 A 
     78         if(vb - i * val[v] < 0) {
     79             break;
     80         }
     81         for(int j = 0; j <= num[3][v]; j++) {
     82             if(sum - va - vb - j * val[v] < 0 || va + (i + j) * val[v] > 1000) {
     83                 break;
     84             }
     85             f[now ^ 1][va + (i + j) * val[v]][vb - i * val[v]] = min(f[now][va][vb] + i + j, f[now ^ 1][va + (i + j) * val[v]][vb - i * val[v]]);    
     86         } 
     87     }
     88     for(int i = 0; i <= num[1][v]; i++) { // BA 给 C
     89         if(va - i * val[v] < 0) {
     90             break;
     91         }
     92         for(int j = 0; j <= num[2][v]; j++) {
     93             if(vb - j * val[v] < 0 || sum - va - vb + (i + j) * val[v] > 1000) {
     94                 break;
     95             }
     96             f[now ^ 1][va - i * val[v]][vb - j * val[v]] = min(f[now][va][vb] + i + j, f[now ^ 1][va - i * val[v]][vb - j * val[v]]);    
     97         } 
     98     }
     99     for(int i = 0; i <= num[1][v]; i++) { // AC 给 B
    100         if(va - i * val[v] < 0) {
    101             break;
    102         }
    103         for(int j = 0; j <= num[3][v]; j++) {
    104             if(sum - va - vb - j * val[v] < 0 || vb + (i + j) * val[v] > 1000) {
    105                 break;
    106             }
    107             f[now ^ 1][va - i * val[v]][vb + (i + j) * val[v]] = min(f[now][va][vb] + i + j, f[now ^ 1][va - i * val[v]][vb + (i + j) * val[v]]);    
    108         } 
    109     }
    110 }
    111 int main()
    112 {
    113     for(int i = 1; i <= 3; i++) {
    114         x[i] = read();
    115     }
    116     for(int i = 1; i <= 3; i++) {
    117         for(int j = 5; j >= 0; j--) {
    118             num[i][j] = read();
    119             s[i] += num[i][j] * val[j];
    120         }
    121         sum += s[i];
    122     }
    123     e[1] = s[1] - x[1] + x[3];
    124     e[2] = s[2] - x[2] + x[1];
    125     e[3] = s[3] - x[3] + x[2];
    126     if(e[1] < 0 || e[2] < 0 || e[3] < 0) {
    127         printf("impossible
    ");
    128         return 0;
    129     }
    130     memset(f, 0x3f, sizeof f);
    131     f[0][s[1]][s[2]] = 0;
    132     for(int i = 0; i < 6; i++) {
    133         for(int j = 0; j <= 1000; j++) {
    134             for(int k = 0; k <= 1000; k++) {
    135                 f[now ^ 1][j][k] = f[now][j][k];    
    136             }
    137         }
    138         int gg = val[i];
    139         for(int j = i + 1; j < 6; j++) {
    140             gg = gcd(val[j], gg);
    141         }
    142         int x = 0, y = 0;
    143         while((e[1] - x) % gg != 0) {
    144             x++;
    145         }
    146         while((e[2] - y) % gg != 0) {
    147             y++;
    148         }
    149         if((e[3] - (sum - x - y)) % gg != 0) {
    150             continue;
    151         }
    152         for(int j = x; j <= 1000; j += gg) {
    153             for(int k = y; k <= 1000; k += gg) {
    154                 if(sum - j - k < 0) {
    155                     break;
    156                 }
    157                 if(f[now][j][k] == inf) {
    158                     continue;
    159                 }
    160                 dp(i, j, k);
    161             }
    162         }
    163         now = now ^ 1;
    164     }
    165     if(f[now][e[1]][e[2]] == inf) {
    166         printf("impossible
    ");
    167     } else {
    168         printf("%d
    ", f[now][e[1]][e[2]]);
    169     }
    170     return 0;
    171 }
    172 
    173 /*
    174 
    175 10 0 0 
    176 
    177 0 1 0 0 0 0 
    178 
    179 0 0 0 3 0 10
    180 
    181 0 0 3 0 0 0 
    182 
    183 */
    View Code
  • 相关阅读:
    二叉树遍历
    NO.35 2021/12/13(06:50)[周一]
    NO.29 2021/11/30(06:30)[周二]
    NO.22 2021/11/19(06:15) [周五]
    The .NET ORM Architec
    C#格式字符串
    C# Attribute
    .net DLL反编译文件
    【Beta】Scrum meeting1
    【Alpha】Scrum meeting 6
  • 原文地址:https://www.cnblogs.com/wuenze/p/8443286.html
Copyright © 2011-2022 走看看