[POJ 1015] Jury Compromise

https://vjudge.net/problem/POJ-1015
题意:
现有\(n\)个人,每个人都有\(p\)值和\(d\)值,现在要选\(k\)个人,先要让他们的\(p\)值和与\(d\)值和的差最小,再让他们的\(p\)值和与\(d\)值和的和最大,并从小到大输出你选的人。

思路:
考虑\(dp[j][w]\),代表选了\(j\)个人,\(p\)值和与\(d\)值和的差为\(w\)时,\(p\)值和与\(d\)值和的和最大值。因为存在负值,所以我们将\(0\)置为\(400\),便于计算。注意\(dp\)转移时,第一维应该为第\(i\)个人,下面选择让他加不加入。听说如果我们第一维枚举选择的人数,当存在多种情况相同时,可能会对最终答案造成影响。例如我们选择\(1\)\(3\)\(5\)\(2\)\(4\)\(6\)时,他们最后的值都相同,那么\(2\)\(4\)\(6\)的方案可能会覆盖掉\(1\)\(3\)\(5\),但如果最终答案应该是\(1\)\(3\)\(5\)\(6\)时,我们就找不到这种情况了。前面不会被后面覆盖的情况亦然。UVA上的题目好像加了这种样例,但是我找了半天样例没搞出来,十分痛苦。
https://vjudge.net/problem/UVA-323

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 27;
const int inf = 0x3f3f3f3f;

int dp[N][N * 40];
int d[207], p[207];
int n, k, cas;
int D, P;
int sta[N], tot;
vector<int> path[N][N * 40];

void gao(int w) {
    for (int i = 0; i < path[k][w].size(); ++i) {
        int v = path[k][w][i];
        P += p[v];
        D += d[v];
        sta[++tot] = v;
    }
    printf("Best jury has value %d for prosecution and value %d for defence:\n", P, D);
    for (int i = 1; i <= tot; ++i) {
        printf(" %d", sta[i]);
    }
    puts("");
}

void solve() {
    for (int i = 1; i <= n; ++i) {
        scanf("%d %d", &p[i], &d[i]);
    }
    for (int i = 0; i <= 20; ++i) {
        for (int j = 0; j <= 800; ++j) {
            path[i][j].clear();
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = min(i, k); j >= 1; --j) {
            for (int w = 0; w <= 800; ++w) {
                int v = w - (d[i] - p[i]);
                if (v < 0 || v > 800) continue;
                if (dp[j][w] < dp[j - 1][v] + d[i] + p[i]) {
                    path[j][w] = path[j - 1][v];
                    path[j][w].push_back(i);
                    dp[j][w] = dp[j - 1][v] + d[i] + p[i];
                }
            }
        }
    }
    printf("Jury #%d\n", ++cas);
    for (int w = 0; w <= 400; ++w) {
        if (dp[k][400 - w] >= 0 && dp[k][400 + w] >= 0) {
            if (dp[k][400 - w] > dp[k][400 + w]) gao(400 - w);
            else gao(400 + w);
            return;
        }
        if (dp[k][400 - w] >= 0) {
            gao(400 - w);
            return;
        }
        if (dp[k][400 + w] >= 0) {
            gao(400 + w);
            return;
        }
    }
}

int main() {
    while (~scanf("%d %d", &n, &k), n | k) {
        memset(dp, -inf, sizeof(dp));
        dp[0][400] = 0;
        D = 0;
        P = 0;
        tot = 0;
        solve();
        puts("");
    }
    return 0;
}
posted @ 2021-03-15 13:51  stff577  阅读(40)  评论(0)    收藏  举报