• POJ #1015


    (poj.org issue. Not submitted yet)

    This is a 2D DP problem, very classic too. Since I'm just learning, so I took this link as reference:

    http://blog.csdn.net/lyy289065406/article/details/6671105

    1. It is a little tricky to pick dependent values for this DP. Again, just think about how you are going to expand this reel gradually. We pick number of chosen persons and min|D-P|

    2. Back-tracing is used to trace paths.

    3. Take care of details.

    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    #include <algorithm>
    
    #define MAX_NUM 400
    #define MAX_CNT 20
    
    //    info per candidate
    int pdiff[MAX_CNT + 1];
    int  psum[MAX_CNT + 1];
    int rpath[MAX_CNT];
    
    //    runtime
    int   dp[MAX_CNT + 1][MAX_NUM * 2 + 1];    // with offset
    int path[MAX_CNT + 1][MAX_NUM * 2 + 1];    // with offset
    
    void Reset()
    {
        memset(  dp, -1, sizeof(int) * ((MAX_NUM * 2 + 1) * (MAX_CNT + 1)));    
        memset(path, -1, sizeof(int) * ((MAX_NUM * 2 + 1) * (MAX_CNT + 1)));
        memset(rpath, -1, sizeof(int) * MAX_CNT);
    }
    
    //    Backtrace: is i selected in dp[p][k]?
    bool select(int i, int p, int k)
    {
        while (p > 0 && path[p][k] != i)
        {        
            k -= pdiff[path[p][k]];
            p--;
        }
        return p ? true : false;
    }
    
    void best_jury(int n, int m, int cnt, int *pd, int *ps)
    {
        Reset();
    
        int fix = m * 20;
        dp[0][fix] = 0;
    
        for (int p = 1; p <= m; p ++)        // each selected m of dp
        for (int k = 0; k <= fix * 2; k ++)    // each hit sum(v) of dp
        {
            if (dp[p-1][k] < 0) continue;
    
            for (int i = 0; i < n; i ++)    // each one
            {
                //    Remember: value of dp[][] is sum(sum)
                int newk = dp[p - 1][k] + psum[i];
                if (newk > dp[p][k + pdiff[i]])
                {
                    if (!select(i, p - 1, k))
                    {
                        // Remember:
                        //    p -> candicate index
                        //    k.. -> current sum(diff)
                          dp[p][k + pdiff[i]] = newk;
                        path[p][k + pdiff[i]] = i;
    //                    printf("- put %d @ %d, %ds
    ", i, p, k + pdiff[i]);
                    }
                }
            }
        }
    
        //    Get min sum(diff)
        int k = -1;
        for (int i = 0; i < fix; i++)
        {
            int v0 = dp[m][fix - i];
            int v1 = dp[m][fix + i];
            if (v0 > 0 || v1 > 0)
            {
                k = i;
                break;
            }
        }
    
        int minSumDiff = dp[m][fix - k] > dp[m][fix + k] ? (fix - k) : (fix + k);    // pick the bigger sum one
    
        int ttlDiff = (dp[m][minSumDiff] + minSumDiff - fix) / 2;
        int ttlSum = (dp[m][minSumDiff] - minSumDiff + fix) / 2;
    
        //
        printf("Jury #%d
    ", cnt);
        printf("Best jury has value %d for prosecution and value %d for defence:
    ", ttlDiff, ttlSum);
        
        //    Output selected in order
        int tmpk = minSumDiff;
        int id_inx = 0;
        while (m > 0 && path[m][tmpk] >= 0)
        {
            rpath[id_inx++] = path[m][tmpk];        
            tmpk -= pdiff[path[m][tmpk]];        
            m--;
        }
        std::sort(rpath, rpath + id_inx);
        for (int i = 0; i < id_inx; i ++)
        {
            printf(" %d", rpath[i] + 1); // real inx starting from 1
        }
        printf("
    
    ");
    }
    
    int main()
    {
        int m, n, cnt = 0;
        int pi[MAX_NUM];
        int di[MAX_NUM];
    
        while (    scanf("%d", &n), scanf("%d", &m), cnt ++, 
                (m != 0) && (n != 0) )
        {    
            //    Get Input            
            for (int i = 0; i < n; i ++)
            {
                scanf("%d%d", pi + i, di + i);
                pdiff[i] = pi[i] - di[i];
                psum[i]  = pi[i] + di[i];
            }
            
            //
            Reset();
            best_jury(n, m, cnt, pdiff, psum);
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    5.7填数字游戏求解
    5.6判断回文数字
    5.5百钱买百鸡问题
    5.4三色球问题
    5.3哥德巴赫猜想的近似证明
    5.2求两个数的最大公约数和最小公倍数
    5.1舍罕王的失算
    4.19递归反向输出字符串
    Elasticsearch 安装
    linux 安装nginx步骤
  • 原文地址:https://www.cnblogs.com/tonix/p/3803353.html
Copyright © 2020-2023  润新知