zoukankan      html  css  js  c++  java
  • [bzoj1021][SHOI2008]Debt 循环的债务 (动态规划)

    Description

    Alice、 Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题。不过,鉴别钞票的真伪是一件很麻烦的事情,于是他 们决定要在清还债务的时候尽可能少的交换现金。比如说,Alice欠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)表示从初始状态到“A手中持有i元,B手中持有j元,C手中持有Sum-i-j元”这一状态需要的最少操作数,然后dp即——

         ——等等……这里转移方向是加减两个方向都可以啊?不可能是dp吧……?

         于是我就在网上看了巨神们的题解……

         啊……看来又是我蠢了……

         他们的思路大概是这样的……考虑这样一个事实:对于同样一种面值的纸币,最优解中不可能出现“A给B,B给C”这样的循环交付,否则我们只要让A直接给C就可以得到更优的解。于是我们就可以从面值来枚举,对每种面值分别dp更新答案。

         代码应该也比较好懂吧,只不过我写得似乎太冗长了……

     1 /**************************************************************
     2     Problem: 1021
     3     User: AsmDef
     4     Language: C++
     5     Result: Accepted
     6     Time:488 ms
     7     Memory:8648 kb
     8 ****************************************************************/
     9  
    10 /***********************************************************************/
    11 /**********************By Asm.Def-Wu Jiaxin*****************************/
    12 /***********************************************************************/
    13 #include <cstdio>
    14 #include <cstring>
    15 #include <cstdlib>
    16 #include <ctime>
    17 #include <cctype>
    18 #include <algorithm>
    19 using namespace std;
    20 template<class T>inline void getd(T &x){
    21     char ch = getchar();bool neg = false;
    22     while(!isdigit(ch) && ch != '-')ch = getchar();
    23     if(ch == '-')ch = getchar(), neg = true;
    24     x = ch - '0';
    25     while(isdigit(ch = getchar()))x = x * 10 - '0' + ch;
    26     if(neg)x = -x;
    27 }
    28 /***********************************************************************/
    29 const int maxn = 1002, INF = 0x3f3f3f3f, val[6] = {15102050100};
    30  
    31 int cnt[3][6], tot[6], Cur[3], Tar[2], Sum, f[2][maxn][maxn];//Tar[]: 目标状态
    32  
    33 inline void init(){
    34     int a, b, c;
    35     getd(a), getd(b), getd(c);
    36     for(int i = 0;i < 3;++i)for(int j = 5;j >= 0;--j){
    37         getd(cnt[i][j]);
    38         Cur[i] += cnt[i][j] * val[j];
    39         tot[j] += cnt[i][j];
    40     }
    41     Sum = Cur[0] + Cur[1] + Cur[2];
    42     Tar[0] = Cur[0] - a + c;
    43     Tar[1] = Cur[1] - b + a;
    44  
    45     if(Tar[0] < 0 || Tar[1] < 0 || Sum - Tar[0] - Tar[1] < 0){
    46         printf("impossible ");
    47         exit(0);
    48     }
    49 }
    50  
    51 #define UPD(a, b) (a = min(a, b) )
    52 #include <cmath>
    53  
    54 inline void work(){
    55     const int rang = Sum + 1;
    56     int i, j, k, a, b, t, tmp, da, db, cnta, cntb;
    57     bool cur, las;
    58     for(i = 0;i <= Sum;++i)memset(f[1][i], 0x3fsizeof(int) * rang);
    59     f[1][Cur[0]][Cur[1]] = 0;
    60     for(i = 0;i < 6;++i){//枚举面值
    61         cur = i & 1, las = cur ^ 1;
    62         for(j = 0;j <= Sum;++j)memset(f[cur][j], 0x3fsizeof(int) * rang);
    63         for(j = 0;j <= Sum;++j){
    64             t = Sum - j;
    65             for(k = 0;k <= t;++k){//枚举A,B两人的当前资产
    66                 if(f[las][j][k] == INF)continue;
    67                 UPD(f[cur][j][k], f[las][j][k]);
    68                 for(a = 0;a <= tot[i];++a){
    69                     tmp = tot[i] - a;
    70                     for(b = 0;b <= tmp;++b){//枚举当前硬币的目标数量
    71                         da = a - cnt[0][i], db = b - cnt[1][i];
    72                         cnta = j + da * val[i], cntb = k + db * val[i];
    73                         if(cnta < 0 || cntb < 0 || cnta + cntb > Sum)continue;
    74                         UPD(f[cur][cnta][cntb], f[las][j][k] + (abs(da) + abs(db) + abs(da + db)) / 2);
    75                     }
    76                 }
    77             }
    78         }
    79     }
    80     if(f[cur][Tar[0]][Tar[1]] == INF)printf("impossible ");
    81     else printf("%d ", f[cur][Tar[0]][Tar[1]]);
    82 }
    83  
    84 int main(){
    85 #ifdef DEBUG
    86     freopen("test.txt""r", stdin);
    87 #elif not defined ONLINE_JUDGE
    88     freopen(".in""r", stdin);
    89     freopen(".out""w", stdout);
    90 #endif
    91     init();
    92     work();
    93  
    94 #ifdef DEBUG
    95     printf(" %.2lf sec  ", (double)clock() / CLOCKS_PER_SEC);
    96 #endif
    97     return 0;
    98 }
    动态规划
  • 相关阅读:
    位图 与矢量图对比
    用ocam工具录视频及转换视频 ffmpeg
    教学设计-饭后百步走
    教学设计例--跟小猴子一起玩
    教学设计-妈妈跳舞
    教学设计--Scratch2.0入门介绍
    Scratch2.0在线注册用户并使用帮助
    下载Scratch2.0离线版并安装教程
    把Sratch作品转为swf文件
    跟小猴子开心玩
  • 原文地址:https://www.cnblogs.com/Asm-Definer/p/4372749.html
Copyright © 2011-2022 走看看