Jury Compromise POJ - 1015 双塔DP 输出路径

题目链接

题意

n个陪审团的候选人,从这n个人中选m人组成陪审团。
选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。

思路

DP过程
dp状态:
用三维DP dp[i][j][k]表示第i个人已经选择了j个人差值为k的总分和
转移:
选择当前点,不选择当前点求max。
处理偏移量
因为k这维度会出现负数;又因为最小为-400,最大为400,
所以我们需要将范围设为
0-800 。然后我们从中值出发,往左右移动,得到最小的体积。

理解是这样理解,反映到代码上,是将 dp[0][0][400]=0;其余设为负无穷。

输出路径
复原路径可以从dp[n][m][v]出发(dp[n][m][v]是我们找到的答案)逆推到dp[x][0][y] (x,y未知),根据dp值之间的关系,把路径给复原出来。
具体看代码吧。

代码

#include <vector>
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>
#define endl '\n'
// #define int long long
using namespace std;
const int N = 205, M = 805;
int n, m;
int a[N], b[N];
int dp[N][21][M];
void solve()
{
    int kcase = 0;
    while (cin >> n >> m && n && m)
    {
        cout << "Jury #" << ++kcase << endl;
        for (int i = 1; i <= n; i++)
            cin >> a[i] >> b[i];

        memset(dp, -0x3f, sizeof dp);
        dp[0][0][400] = 0;

        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= m; j++)
                for (int k = 0; k < M; k++)
                {
                    dp[i][j][k] = dp[i - 1][j][k];
                    int t = k - (a[i] - b[i]);
                    if (t < 0 || t >= M)  continue;
                    if (j < 1) continue;
                    dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - 1][t] + a[i] + b[i]);
                }

        int v = 0;
        //有一个大于0就停止
        while (dp[n][m][400 - v] < 0 && dp[n][m][400 + v] < 0)
            v++;
        if (dp[n][m][400 - v] > dp[n][m][400 + v])
            v = 400 - v;
        else
            v = 400 + v;

        int asum = 0, bsum = 0;
        int i = n, j = m;
        stack<int> ans;
        while (j)
        {
            if (dp[i][j][v] == dp[i - 1][j][v])
                i--;
            else
            {
                asum += a[i], bsum += b[i];
                ans.push(i);
                v -= (a[i] - b[i]);
                i--, j--;
            }
        }
        printf("Best jury has value %d for prosecution and value %d for defence:\n", asum, bsum);
        while (ans.size())
        {
            int k = ans.top();
            ans.pop();
            cout << k << " ";
        }
        printf("\n\n");
    }
}

signed main()
{
    // ios::sync_with_stdio(false);
    // cin.tie(0);
    // cout.tie(0);
    int t = 1;
    // cin >> t;
    while (t--)
        solve();
    return 0;
}
posted @ 2022-08-06 10:33  kingwzun  阅读(30)  评论(0编辑  收藏  举报