您的位置:首页 > 编程语言 > Go语言

poj1015——Jury Compromise

2014-08-23 15:55 239 查看
题意:n(1~200)个候选人,辩方和控方分别对他们打分(0~20)分别为p、d,从其中选出m个人,要求——这m个人辩方总分和控方总和的差值最小,如果存在多种情况则选辩方、控方总和最大的。

输入:n,m,p[i],d[i]

输出:sum(p[i]),sum(d[i]),选择的m个人(按编号的升序)

分析:动态规划

   1、用到2个数组——dp[i][j]:表示取i个候选人,使其辩控差为j的所有方案中,辩控和最大的方案的辩控和

                    path[i][j]:记录所选定的候选人的编号

   2、由于辩控差可以为负数,而我们要保证dp[i][j]中j的非负性,所以设置一个修正值real_m=m*20,这样辩控差                    区间从[-400,400]变成[0,800]

   3、主体就是三重循环——i从1到m,j从0到2*real_m,k从1到n,找到满足条件的k就可以记录到path数组中去,
        详情见代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct P
{
int sum,sub;
};
P caipan[201];
int path[21][801],dp[21][801];

bool OK(int a,int b,int c)
{
while(a>0&&path[a][b]!=c)
{
b-=caipan[path[a][b]].sub;
a--;
}
if(a==0)return true;
else return false;
}

int main()
{
int n,m,i,j,k,cas=1,id[21];
while(scanf("%d%d",&n,&m),n+m)
{
memset(caipan,0,sizeof(caipan));
for(i=1;i<=n;i++)
{
int p,d;
scanf("%d%d",&p,&d);
caipan[i].sum=p+d;
caipan[i].sub=p-d;
}

memset(dp,-1,sizeof(dp));
memset(path,0,sizeof(path));
int real_m=m*20;
dp[0][real_m]=0;
for(i=1;i<=m;i++)
for(j=0;j<=2*real_m;j++)
if(dp[i-1][j]>=0)
{
for(k=1;k<=n;k++)
if(dp[i][j+caipan[k].sub]<dp[i-1][j]+caipan[k].sum&&OK(i-1,j,k))
{
dp[i][j+caipan[k].sub]=dp[i-1][j]+caipan[k].sum;
path[i][j+caipan[k].sub]=k;
}
}

for(k=0;k<=real_m;k++)
if(dp[m][real_m-k]>=0||dp[m][real_m+k]>=0)break;
int tmp=dp[m][real_m-k]>dp[m][real_m+k]?(real_m-k):(real_m+k);
//printf("+++%d\n",tmp);
int sum_p=(dp[m][tmp]+(tmp-real_m))/2;
int sum_d=(dp[m][tmp]-(tmp-real_m))/2;
for(i=m,j=0;i>0;i--)
{
id[j]=path[i][tmp];
tmp-=caipan[path[i][tmp]].sub;
j++;
}
sort(id,id+m);

printf("Jury #%d\n",cas++);
printf("Best jury has value %d for prosecution and value %d for defence:\n",sum_p,sum_d);
for(i=0;i<m;i++)
printf(" %d",id[i]);
printf("\n\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息