1. 程式人生 > >POJ1015 Jury Compromise

POJ1015 Jury Compromise

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