poj1015Jury Compromise

来源:互联网 发布:织梦cms增加前台模块 编辑:程序博客网 时间:2024/05/16 19:23
完完全全用自己的思路做了一道dp题,感觉对dp的理解又加深了一层
题目其实可以抽象为:从n个数对里面选出m个数对,使得所有数对的第一个数字之和与第二个数字之和的差尽量接近于0且所有数字之和尽量大。

如果直接从两部分的差值最小来设计状态转移的话很困难,因为如果子问题的差值的绝对值最小,不一定总体的差值绝对值最小。考虑到题目的数据量不算太大,可以考虑通过每个差值的最大数字之和来设计状态转移,这样最优子结构就很明显了。最后只需要找到到差值最接近于0的解就可以了。

#include<cstdio>#include<cstring>#include<algorithm>#define MAXN 210#define MAXM 25using namespace std;int dp[MAXN][MAXM][MAXM*40],s[MAXN][2],father[MAXN][MAXM][MAXM*40],sum[MAXN],sub[MAXN];int ans[MAXM],prosecution,defence;void dfs(int n,int m,int maxxid){    if(m==0)        return ;    if(dp[n][m][maxxid]!=dp[n-1][m][maxxid]){        ans[m]=n,prosecution+=s[n][0],defence+=s[n][1];        dfs(n-1,m-1,maxxid-sub[n]);    }    else        dfs(n-1,m,maxxid);}int main(){    int n,m,cases=1;    while(scanf("%d %d",&n,&m)&&m+n){        for(int i=1;i<=n;i++){            scanf("%d %d",&s[i][0],&s[i][1]);            sum[i]=s[i][0]+s[i][1];            sub[i]=s[i][0]-s[i][1]+20;        }        printf("Jury #%d\n",cases++);        prosecution=0,defence=0;        memset(dp,-1,sizeof(dp));        for(int i=0;i<=n;i++)            dp[i][0][0]=0;        for(int i=1;i<=n;i++){            for(int j=1;j<=i&&j<=m;j++){                for(int t=0;t<=m*40;t++){                    if(t-sub[i]>=0&&dp[i-1][j-1][t-sub[i]]>=0)                        dp[i][j][t]=dp[i-1][j-1][t-sub[i]]+sum[i];                    if(dp[i][j][t]<dp[i-1][j][t])                        dp[i][j][t]=dp[i-1][j][t];                }            }        }        int flag=0,maxxid=-1;        for(int i=0;i<=20*m;i++){            if(dp[n][m][20*m+i]!=-1){                flag=1;                maxxid=20*m+i;            }            if(dp[n][m][20*m-i]!=-1){                flag=1;                if(dp[n][m][20*m-i]>dp[n][m][maxxid])                    maxxid=20*m-i;            }            if(flag)                break;        }        dfs(n,m,maxxid);        printf("Best jury has value %d for prosecution and value %d for defence:\n",prosecution,defence);        for(int i=1;i<=m;i++)            printf(" %d",ans[i]);        printf("\n\n");    }    return 0;}


0 0
原创粉丝点击