<<算法竞赛进阶指南>>:陪审团
在一個遙遠(yuǎn)的國家,一名嫌疑犯是否有罪需要由陪審團來決定。
陪審團是由法官從公民中挑選的。
法官先隨機挑選 NNN 個人(編號 1,2…,N1,2…,N1,2…,N)作為陪審團的候選人,然后再從這 NNN 個人中按照下列方法選出 MMM 人組成陪審團。
首先,參與訴訟的控方和辯方會給所有候選人打分,分值在 000 到 202020 之間。
第 iii 個人的得分分別記為 p[i]p[i]p[i] 和 d[i]d[i]d[i]。 為了公平起見,法官選出的 MMM 個人必須滿足:辯方總分 DDD 和控方總分 PPP 的差的絕對值 ∣D?P∣|D?P|∣D?P∣ 最小。
如果選擇方法不唯一,那么再從中選擇辨控雙方總分之和 D+PD+PD+P 最大的方案。求最終的陪審團獲得的辯方總分 DDD、控方總分 PPP,以及陪審團人選的編號。
注意:若陪審團的人選方案不唯一,則任意輸出一組合法方案即可。
輸入格式:
輸入包含多組測試數(shù)據(jù)。
每組測試數(shù)據(jù)第一行包含兩個整數(shù) NNN 和 MMM。
接下來 NNN 行,每行包含兩個整數(shù) p[i]p[i]p[i] 和 d[i]d[i]d[i]。
每組測試數(shù)據(jù)之間隔一個空行。
當(dāng)輸入數(shù)據(jù) N=0,M=0N=0,M=0N=0,M=0 時,表示結(jié)束輸入,該數(shù)據(jù)無需處理。
輸出格式:
對于每組數(shù)據(jù),第一行輸出 KaTeX parse error: Expected 'EOF', got '#' at position 6: Jury #?C,CCC
為數(shù)據(jù)編號,從 111 開始。
第二行輸出 BestjuryhasvaluePforprosecutionandvalueDfordefence:Best jury has value P for prosecution and value D for defence:BestjuryhasvaluePforprosecutionandvalueDfordefence:,PPP為控方總分,DDD 為辯方總分。
第三行輸出按升序排列的陪審人選編號,每個編號前輸出一個空格。
每組數(shù)據(jù)輸出完后,輸出一個空行。
數(shù)據(jù)范圍:
1≤N≤2001≤N≤2001≤N≤200
1≤M≤201≤M≤201≤M≤20
0≤p[i],d[i]≤200≤p[i],d[i]≤200≤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
首先 遇到背包問題, 確定背包類型, 每個人只能選一個, 故為 010101 背包, 然后題目要求具體方案, 首先答案要求滿足兩個條件, 第一是要 ∣D?P∣|D - P|∣D?P∣ 最小,其次是 D+PD + PD+P 最大, 我們可以將 D+PD + PD+P 定義為背包的屬性
狀態(tài)定義: f[i][j][k]f[i][j][k]f[i][j][k]: 在前 iii 個人中選, 總?cè)藬?shù)不超過 jjj, 并且總差值為 kkk 的集合
狀態(tài)屬性: D+PD + PD+P 的最大值
狀態(tài)計算: 選第 iii 個人 不選第 iii 個人
f[i][j][k]=max(f[i?1][j][k],f[i?1][j?1][k?(p[i]?d[i])]+p[i]+d[i]);f[i][j][k] = max(f[i - 1][j][k], f[i - 1][j - 1][k - (p[i] - d[i])] + p[i] + d[i]);f[i][j][k]=max(f[i?1][j][k],f[i?1][j?1][k?(p[i]?d[i])]+p[i]+d[i]);
求出 D+PD + PD+P 的最大值并不難, 難點在于如何得到具體方案,我們可以通過方向搜一遍, 如果從終點狀態(tài),一直迭代到起始狀態(tài),能夠進(jìn)行狀態(tài)轉(zhuǎn)移,我們就記下這個方案
注意: 由于p[i] 是從 111 ~ 202020, 所以 p[i]?d[i]p[i] - d[i]p[i]?d[i] 是從 ?40-40?40 ~ 404040, 所以總的 p[i]?d[i]p[i] - d[i]p[i]?d[i] 是從 ?400-400?400 ~ 400400400, 但是如果直接使用,會導(dǎo)致數(shù)組越界,所以我們加上一個偏移量取名為 basebasebase,其值 400400400, 故差值的范圍就會變成 000 ~ 800800800
#include<bits/stdc++.h>using namespace std;const int N = 210, M = 810, base = 400;int f[N][21][M], p[N], d[N], ans[N], n, m;int main() {int T = 1;while(cin >> n >> m, n, m){for(int i = 1; i <= n; i ++ ) cin >> p[i] >> d[i]; //讀入memset(f, -0x3f, sizeof f); //因為求最大值, 故賦值為負(fù)無窮f[0][0][base] = 0; //初始化為0int cnt = 0; //初始化for(int i = 1; i <= n; i ++) //枚舉前i個人for(int j = 0; j <= m; j ++) //枚舉已經(jīng)選了的人for(int k = 0; k < M; k ++ ) //枚舉差值 0~801{f[i][j][k] = f[i - 1][j][k]; //不選第 i 個人int t = k - (p[i] - d[i]); //計算出差值,看是否符合題意if(t < 0 || t > M ) continue; if(j < 1) continue; //是否可以轉(zhuǎn)移f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][t] + p[i] + d[i]); //狀態(tài)轉(zhuǎn)移}int v = 0;while( f[n][m][base + v] < 0 && f[n][m][base - v] < 0) v ++;// 當(dāng)v小于0和v大于0 都不合題意是, v++;if(f[n][m][base + v] > f[n][m][base - v]) v = base + v;else v = base - v;//當(dāng)v,-v都存在時,取最大值int j = m, i = n, k = v;while(j){if(f[i][j][k] == f[i - 1][j][k]) i --;//如果可以不選第i個人else {ans[cnt ++ ] = i; //選了第i個人k -= p[i] - d[i]; //差值減小i --, j --; //減小}}int a = 0, b = 0;for(int i = 0; i < cnt; i ++ ) a += p[ans[i]], b += d[ans[i]];//記錄答案printf("Jury #%d\n", T++);printf("Best jury has value %d for prosecution and value %d for defence:\n", a, b);sort(ans, ans + cnt); //排序,保證編號是從小到大的//打印方案for(int i = 0; i < cnt; i ++ ) cout << ans[i] << ' ';cout << '\n';cout << '\n';} }總結(jié)
以上是生活随笔為你收集整理的<<算法竞赛进阶指南>>:陪审团的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 事件循环、webpack、vue<前端学
- 下一篇: 百度推出新版团购导航 对团购导航造成冲击