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

    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1021

    【题意】

    【题解】

    设f[i][j][k]表示前i种面值的钱币;
    第一个人当前的钱数为j,第二个人当前的钱数为k;
    所需要的最小交换钱币次数;
    这里第三个人的钱数就是sum-j-k;
    然后我们以钱币的种类划分成6个阶段进行这样的DP;
    (这里我们可以一开始通过a,b,c处理出最后第一个人该有多少钱、第二个人该有多少钱…)
    DP的依据就是;
    同一种类的钱币;
    只要确定了某个人要增加或者减少多少个这种类型的钱币个数;
    那么最佳的方案就确定了;
    即不会出现从A转到B再转到C的情况。
    对于这种,A可以直接转到C..
    那么也就是说
    这种类型的钱如果第一个人的改变量为da,第二个人的改变量为db;
    那么最小的交换次数就能确定;
    即(abs(da)+abs(db)+abd(da+db))/2
    这是最佳的方案;
    (同一种钱币)
    根据这个规则
    枚举第一个人的钱数、第二个人的钱数、这种钱币第一个人最后有多少张,第二个人有多少张.
    进行一个类似背包的DP就好.

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    #define ref(x) scanf("%lf",&x)
    
    typedef pair<int, int> pii;
    typedef pair<LL, LL> pll;
    
    const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
    const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
    const int val[7] = { 0,1,5,10,20,50,100 };
    const double pi = acos(-1.0);
    const int N = 1e3+100;
    const int INF = 0x3f3f3f3f;
    
    int total[4], cnt[4][7],tot[7],sum;
    int f[2][N][N],a,b,c,target[3],pre,now;
    
    #define UPD(x,y) (x = min(x,y))
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        rei(a), rei(b), rei(c);
        rep1(i, 1, 3)
            rep2(j, 6, 1)
            {
                rei(cnt[i][j]);
                total[i] += val[j] * cnt[i][j];
                tot[j] += cnt[i][j];
                sum += val[j] * cnt[i][j];
            }
        target[1] = total[1] - a + c;
        target[2] = total[2] - b + a;
        if (target[1] < 0 || target[2] < 0 || sum - target[1] - target[2] < 0)
        {
            puts("impossible");
            return 0;
        }
    
        pre = now = 0;
        memset(f[pre], INF, sizeof f[pre]);
        f[pre][total[1]][total[2]] = 0;
        rep1(i, 1, 6)
        {
            pre = now;
            now = now ^ 1;
            memset(f[now], INF, sizeof f[now]);
            rep1(j, 0, sum)
            {
                int t = sum - j;
                rep1(k, 0, t)
                {
                    if (f[pre][j][k] == INF) continue;
                    UPD(f[now][j][k], f[pre][j][k]);
                    //assert f[pre][j][k]!=INF
                    rep1(q, 0, tot[i])
                    {
                        int r = tot[i] - q;
                        rep1(w, 0, r)
                        {
                            int da = q - cnt[1][i], db = w - cnt[2][i];
                            int cnta = j + da*val[i], cntb = k + db*val[i];
                            if (cnta < 0 || cntb < 0 || sum - cnta - cntb < 0) continue;
                            UPD(f[now][cnta][cntb], f[pre][j][k] + (abs(da) + abs(db) + abs(da + db)) / 2);
                        }
                    }
                }
            }
        }
        if (f[now][target[1]][target[2]] == INF) return puts("impossible"), 0;
        printf("%d
    ", f[now][target[1]][target[2]]);
        //printf("
    %.2lf sec 
    ", (double)clock() / CLOCKS_PER_SEC);
        return 0;
    }
    
  • 相关阅读:
    SQL去除重复记录
    FullCalendar应用——整合农历节气和节日
    Dropzone.js实现文件拖拽上传
    HTML5实现文件断点续传
    FullCalendar日历插件说明文档
    网络电影免会员播放器
    百度网盘搜索工具
    HTML5学习
    HTML2 -- 布局格式
    JS10 -- url问号后的数据
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626567.html
Copyright © 2011-2022 走看看