陪审团

在一个遥远的国家,一名嫌疑犯是否有罪需要由陪审团来决定。

陪审团是由法官从公民中挑选的。

法官先随机挑选N个人(编号1,2…,N)作为陪审团的候选人,然后再从这N个人中按照下列方法选出M人组成陪审团。

首先,参与诉讼的控方和辩方会给所有候选人打分,分值在0到20之间。

第 i 个人的得分分别记为p[i]和d[i]。

为了公平起见,法官选出的M个人必须满足:辩方总分D和控方总分P的差的绝对值|D-P|最小。

如果选择方法不唯一,那么再从中选择辨控双方总分之和D+P最大的方案。

求最终的陪审团获得的辩方总分D、控方总分P,以及陪审团人选的编号。

注意:若陪审团的人选方案不唯一,则任意输出一组合法方案即可。

输入格式
输入包含多组测试数据。

每组测试数据第一行包含两个整数N和M。

接下来N行,每行包含两个整数p[i]和d[i]。

每组测试数据之间隔一个空行。

当输入数据N=0,M=0时,表示结束输入,该数据无需处理。

输出格式
对于每组数据,第一行输出’Jury #C’,C为数据编号,从1开始。

第二行输出“Best jury has value P for prosecution and value D for defence:”,P为控方总分,D为辩方总分。

第三行输出按升序排列的陪审人选编号,每个编号前输出一个空格。

每组数据输出完后,输出一个空行。

数据范围
1≤N≤200,
1≤M≤20
0≤p[i],d[i]≤20

输入样例:
4 2
1 2
2 3
4 1
6 2
0 0
输出样例:
Jury #1
Best jury has value 6 for prosecution and value 4 for defence:
 2 3

起初使用01背包维护辩方总分D和控方总分P的差的绝对值|D-P|最小和辨控双方总分之和D+P最大,结果WA了,经分析发现,|D-P|中的D-P有正负,会影响结果。

#include<bits/stdc++.h>

#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N = 205, M = 25;
int p[N], d[N], f[M][2], n, m, T;
pii pre[N][M];

int main() {
    while (scanf("%d%d", &n, &m), n && m) {
        for (int i = 1; i <= n; i++)scanf("%d%d", &p[i], &d[i]);
        memset(pre, 0, sizeof(pre));
        memset(f, -0x3f, sizeof(f));
        f[0][0] = f[0][1] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = min(i, m); j >= 1; j--) {
                int val1 = f[j - 1][0] + d[i] - p[i];
                int val2 = f[j - 1][1] + d[i] + p[i];
                if (abs(val1) < abs(f[j][0]))
                    f[j][0] = val1, f[j][1] = val2, pre[i][j] = {i - 1, j - 1};
                else if (abs(val1) == abs(f[j][0]) && val2 > f[j][1])
                    f[j][0] = val1, f[j][1] = val2, pre[i][j] = {i - 1, j - 1};
                else pre[i][j] = pre[i - 1][j];
            }
        }
        printf("Jury #%d\n", ++T);
        printf("Best jury has value %d for prosecution and value %d for defence:\n", (f[m][1] - f[m][0]) / 2,
               (f[m][0] + f[m][1]) / 2);
        pii res = {n, m};
        vector<int> ans;
        while (res.se) {
            if (res.se > pre[res.fi][res.se].se)
                ans.push_back(pre[res.fi][res.se].fi + 1);
            res = pre[res.fi][res.se];
        }
        for (int i = ans.size() - 1; i >= 0; i--)printf(" %d", ans[i]);
        puts("\n");
    }
    return 0;
}

正确做法

#include<bits/stdc++.h>

using namespace std;
const int N = 210, M = 810, base = 400;
int n, m, p[N], d[N], T;
int f[N][21][M];
int ans[21];

int main() {
    while (scanf("%d%d", &n, &m), n && m) {
        for (int i = 1; i <= n; i++)scanf("%d%d", &p[i], &d[i]);
        memset(f, -0x3f, sizeof(f));
        f[0][0][base] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= min(m, i); j++)
                for (int k = 0; k < M; k++) {
                    f[i][j][k] = f[i - 1][j][k];
                    if (j < 1)continue;
                    int t = k - (d[i] - p[i]);
                    if (t >= M || t < 0)continue;
                    f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][t] + p[i] + d[i]);
                }
        int v = 0, bv;
        while (f[n][m][base - v] < 0 && f[n][m][base + v] < 0)v++;
        if (f[n][m][base - v] < f[n][m][base + v])bv = base + v;
        else bv = base - v, v = -v;
        int i = n, j = m, k = bv, cnt = 0;
        while (j)
            f[i][j][k] == f[i - 1][j][k] ? (i--) : (ans[++cnt] = i, k -= (d[i] - p[i]), i--, j--);
        printf("Jury #%d\n", ++T);
        printf("Best jury has value %d for prosecution and value %d for defence:\n", (f[n][m][bv] - v) / 2,
               (f[n][m][bv] + v) / 2);
        for (int tc = cnt; tc >= 1; tc--)printf(" %d", ans[tc]);
        puts("\n");
    }
    return 0;
}
发布了329 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45323960/article/details/104736884
今日推荐