POJ 1015 Jury Compromise

題目大意:有n個人,每個人都有兩種評價,第i個人的評價分別爲d[i],p[i]。然後給你一個m,讓你從中選出m個人,使方案最優,最優方案定義爲:令選出m個人的集合爲M,則(1)| ∑d[i] - ∑p[i] | 最小,i∈M;(2)在| ∑d[i] - ∑p[i] | 相同的多種方案中,選∑d[i] +∑p[i] 最大的,i∈M。最後輸出∑d[i] 和∑p[i]的值,以及被選上人的編號。

思路:這道題是道DP題,但我始終沒有想出遞推公式,因爲我沒有想到把| ∑d[i] - ∑p[i] |作爲遞推參數。由於題目給出等級範圍爲0~20,因此m最大爲20的情況下, ∑d[i] - ∑p[i]  的範圍爲[-400,400],這就爲DP提供了可能。

(1)設置dp(i,j),含義爲選出i個人,∑d[i] - ∑p[i] 爲j的情況下,∑d[i] +∑p[i] 最大值。則當前dp(i-1,j)存在有效值時,狀態轉移公式爲:dp(i,j+d[x]-p[x])= max(dp(i,j+d[x]-p[x]),dp[i-1]+d[x]+p[x]),max裏前一個參數代表不選x,後一個代表選x。其中x滿足在dp(i-1,j)方案中,x沒有被選過。

(2)設置path(i,j),含義爲選出i個人,∑d[i] - ∑p[i] 爲j的情況下,最後一個被選上的人的編號,則倒數第二個被選上的人的編號爲path(i-1,j - (d[path(i,j)]-p[path(i,j)])),依次類推,則能找到dp(i,j)方案前i個人的所有編號。

(3)由於數組下標不允許出現負數,所以將dp和path的第二個參數都加上20*m,再進行處理。

 

#include <iostream>
#include <algorithm>

using namespace std;

int n,m,p[205],d[205];
int dp[25][805],path[25][805],ans[25];

bool test(int j,int k,int i)
{
    while (j>0 && path[j][k]!=i)
    {
        k-=(p[path[j][k]]-d[path[j][k]]);
        j--;
    }
    if (j==0)
        return true;
    return false;
}

int main()
{
    int i,j,k,test_cases=1;
    while (scanf("%d%d",&n,&m)==2 && (n||m))
    {
        for (i=1;i<=n;i++)
            scanf("%d%d",&p[i],&d[i]);
        memset(dp,-1,sizeof(dp));
        memset(path,0,sizeof(path));
        dp[0][m*20]=0;
        for (j=1;j<=m;j++)
            for (k=0;k<=m*40;k++)
                if (dp[j-1][k]!=-1)
                    for (i=1;i<=n;i++)
                        if (dp[j][k+p[i]-d[i]]<dp[j-1][k]+p[i]+d[i] && test(j-1,k,i))
                        {
                            dp[j][k+p[i]-d[i]]=dp[j-1][k]+p[i]+d[i];
                            path[j][k+p[i]-d[i]]=i;
                        }
        for (j=0;dp[m][m*20+j]==-1 && dp[m][m*20-j]==-1;j++);
        if (dp[m][m*20+j]>dp[m][m*20-j])
            k=m*20+j;
        else
            k=m*20-j;
        printf("Jury #%d\n",test_cases++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n",(dp[m][k]+k-m*20)/2,(dp[m][k]-k+m*20)/2);
        for (i=0;i<m;i++)
        {
            ans[i]=path[m-i][k];
            k-=(p[path[m-i][k]]-d[path[m-i][k]]);
        }
        sort(ans,ans+m);
        for (i=0;i<m;i++)
            printf(" %d",ans[i]);
        printf("\n\n");
    }
    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章