POJ1015 Jury Compromise
阿新 • • 發佈:2019-02-13
sin sca pac 需要 循環 block scanf rom i++
POJ1015 Jury Compromise
- 我們可以將每個候選人的辯控差作為該物品的體積之一,把辯控和作為物品的價值。
- 因為評價差的總分值最大可能就只有[-400,400],所以我們整體加上20*m
為敘述問題方便,現將任一選擇方案中,辯方總分和控方總分
之差簡稱為“辯控差”,辯方總分和控方總分之和稱為“辯控和”。
第i 個候選人的辯方總分和控方總分之差記為V(i),辯方總分和控
方總分之和記為S(i)。現用f(j, k)表示,取j 個候選人,使其辯
控差為k 的所有方案中,辯控和最大的那個方案(該方案稱為“方
案f(j, k)”)的辯控和。並且,我們還規定,如果沒法選j 個人,
使其辯控差為k,那麽f(j, k)的值就為-1,也稱方案f(j, k)不可行。
本題是要求選出m 個人,那麽,如果對k 的所有可能的取值,求
出了所有的f(m, k) (-20×m≤ k ≤ 20×m),那麽陪審團方案
自然就很容易找到了。
問題的關鍵是建立遞推關系。需要從哪些已知條件出發,
才能求出f(j, k)呢?顯然,方案f(j, k)是由某個可行的方案f(j-1, x)
( -20×m ≤ x ≤ 20×m)演化而來的。可行方案f(j-1, x)能演化成
方案f(j, k)的必要條件是:存在某個候選人i,i 在方案f(j-1, x)中
沒有被選上,且x+V(i) = k。在所有滿足該必要條件的f(j-1, x)中,
選出 f(j-1, x) + S(i) 的值最大的那個,那麽方案f(j-1, x)再加上候選人i,
就演變成了方案 f(j, k)。這中間需要將一個方案都選了哪些人都記錄下來。
不妨將方案f(j, k)中最後選的那個候選人的編號,記在二維數組的
元素path[j][k]中。那麽方案f(j, k)的倒數第二個人選的編號,
就是path[j-1][k-V[path[j][k]]。假定最後算出了解方案的辯控差是k,
那麽從path[m][k]出發,就能順藤摸瓜一步步求出所有被選中的候選人。
初始條件,只能確定f(0, 0) = 0。由此出發,一步步自底向上遞推,
就能求出所有的可行方案f(m, k)( -20×m ≤ k ≤ 20×m)。實際解題
的時候,會用一個二維數組f 來存放f(j, k)的值。而且,由於題目中辯
控差的值k 可以為負數,而程序中數租下標不能為負數,所以,在程序中
不妨將辯控差的值都加上400,以免下標為負數導致出錯,即題目描述中,
如果辯控差為0,則在程序中辯控差為400。
大佬題解
代碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m; int a[330],b[300]; int f[300][1000]; int pat[300][1000]; int zer,t1,t2; int icase; int ans[300]; int i,j,k; int main() { while(scanf("%d%d",&n,&m)) { icase++; if(n==0&&m==0) break; int x,y; memset(f,-1,sizeof(f)); memset(pat,0,sizeof(pat)); for(i=1 ; i<=n ; i++) { scanf("%d%d",&x,&y); a[i]=x-y; b[i]=x+y; } zer=20*m;//題目中的辯控差為0,對應於程序中的辯控差為m*20 f[0][zer]=0; //f[j][k]表示選j個人使其辯控差為k時的最大辯控和 for(j=0 ; j<m ; j++)//每次循環選出1個人 { for(k=0 ; k<=zer*2 ; k++)//枚舉辯控差 if(f[j][k]>=0) { for(i=1 ; i<=n ; i++) if(f[j][k]+b[i]>f[j+1][k+a[i]]) { t1=j;t2=k; while(t1>0&&pat[t1][t2]!=i)//驗證i是否在前面出現過 { t2-=a[pat[t1][t2]]; t1--; } if(t1==0) { f[j+1][k+a[i]]=f[j][k]+b[i]; pat[j+1][k+a[i]]=i; } } } } i=zer,j=0; while(f[m][i+j]<0&&f[m][i-j]<0) j++; if(f[m][i+j]>f[m][i-j]) k=i+j; else k=i-j; int ans1=(f[m][k]+k-zer)/2;//(和+差)/2 int ans2=(f[m][k]-(k-zer))/2;//(和-差)/2 printf("Jury #%d\n",icase); printf("Best jury has value %d for prosecution and value %d for defence:\n",ans1,ans2); for(i=1 ; i<=m ; i++) { ans[i]=pat[m-i+1][k]; k-=a[ans[i]]; } sort(ans+1,ans+m+1); for(i=1 ; i<=m ; i++) printf(" %d",ans[i]); printf("\n\n"); } return 0; }View Code
POJ1015 Jury Compromise