Loading

【dp每日一题】POJ 1015 Jury Compromise

大意:

n个候选人,从中选出m个人。

控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。

思路:

\(dp[i][k]\)代表选了i个人且控辩差为k的情况下,控辩和的最大值。

为了处理方便,需要将k都加上m*20,这样保证所有的k都是大于等于0的。

初始将dp数组赋值为-1,\(dp[0][m*20]=0\),只有当dp数组不等于-1时可以通过这个状态转移,同时需要保证要选的人之前没有选过,那么只需要维护一个pre数组记录达到当前状态选了哪些人即可

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;

const int N = 200 + 5;
typedef long long LL;
int n, m, a[N], b[N], dp[25][1000], maxk, pre[25][1000], res[25];
int cases = 0;
int main() {
    while (cin >> n >> m && (n + m != 0)) {
        cases++;
        memset(dp, -1, sizeof dp);
        memset(pre, -1, sizeof pre);
        for (int i = 0; i < n; i++) {
            cin >> a[i] >> b[i];
        }
        maxk = m * 20;
        dp[0][maxk] = 0;
        for (int i = 0; i < m; i++)
            for (int k = 0; k <= maxk * 2; k++)
                if (dp[i][k] != -1)
                    for (int j = 0; j < n; j++) {
                        if (a[j] + b[j] + dp[i][k] >
                            dp[i + 1][k + a[j] - b[j]]) {
                            int x = i, y = k;
                            while (x > 0 && pre[x][y] != j) {
                                y = y - (a[pre[x][y]] - b[pre[x][y]]);
                                x--;
                            }
                            if (x == 0) {  // j不在路径内
                                pre[i + 1][k + a[j] - b[j]] = j;
                                dp[i + 1][k + a[j] - b[j]] =
                                    a[j] + b[j] + dp[i][k];
                            }
                        }
                    }
        int k = 0;
        for (k = 0; k <= maxk; k++) {
            if (dp[m][k + maxk] != -1) break;
            if (dp[m][-k + maxk] != -1) break;
        }
        if (dp[m][k + maxk] > dp[m][-k + maxk])
            k = k + maxk;
        else
            k = maxk - k;
        cout << "Jury #" << cases << endl;
        cout << "Best jury has value " << (k - maxk + dp[m][k]) / 2
             << " for prosecution and value " << (dp[m][k] - k + maxk) / 2
             << " for defence: " << endl;
        for (int i = m; i > 0; i--) {
            res[i-1] = pre[i][k]+1;
            k = k - (a[pre[i][k]] - b[pre[i][k]]);
        }
        sort(res, res + m);
        for (int i = 0; i < m; i++) cout << ' ' << res[i];
        cout << endl;
    }
    return 0;
}
posted @ 2020-12-30 00:47  dyhaohaoxuexi  阅读(65)  评论(0编辑  收藏  举报