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
原文地址:https://www.cnblogs.com/tonix/p/3803353.html