pku1015Jury Compromise 动态规划

题目大意:

在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是:控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。

代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 int dp[21][802];
 5 //dp[i][j]表示取i个候选人,使其辩控差为j的所有方案中
 6 //辩控和最大的那个方案,dp[i][j]存的是辩控和
 7 int path[21][802];
 8 //用来记录选了哪些人
 9 //方案dp[i][j]中最后选的那个候选人的编号,记在path[i][j]中
10 int plus[202];//辩控和
11 int minus[202];//辩控差
12 int ans[21];//存放最终方案的人选
13 int compare(const void *a,const void *b)
14 {
15     return (*(int *)a)-(*(int *)b);
16 }
17 int main()
18 {
19     int i,j,k,t1,t2,ii,jj,n,m;
20     int base;//由于辩控差可能为负,所以可以加上这个来映射成为正值:m×20
21     int casenum=0;
22 
23     while(scanf("%d %d",&n,&m),n||m)
24     {
25         casenum++;base=20*m;
26         for(i=1;i<=n;i++)
27         {
28             scanf("%d %d",&t1,&t2);
29             plus[i]=t1+t2;minus[i]=t1-t2;
30         }
31         memset(dp,-1,sizeof(dp));
32         memset(path,-1,sizeof(path));
33         dp[0][base]=path[0][base]=0;//选0个人使得辩控差为0的方案,其辩控和也为0
34         for(j=0;j<m;j++)        
35             for(k=0;k<=2*base;k++)
36             {
37                 if(dp[j][k]>=0)        //方案dp[j][k]可行
38                     for(i=1;i<=n;i++){            //找下一个人
39                         if(dp[j+1][k+minus[i]]<dp[j][k]+plus[i]){
40                             //判断第i个人是否已经在方案dp[j][k]上了
41                             for(ii=j,jj=k;ii>=1;ii--)
42                             {
43                                 if(path[ii][jj]==i)    break;
44                                 jj-=minus[path[ii][jj]];
45                             }
46                             //没有被选上
47                             if(ii<1)
48                             {
49                                 path[j+1][k+minus[i]]=i;              //记录
50                                 dp[j+1][k+minus[i]]=dp[j][k]+plus[i];
51                             }
52                         
53                         }
54                     }
55             }
56             //找辩控差绝对值最小的方案
57             i=base;
58             for(j=0;dp[m][i+j]<0&&dp[m][i-j]<0;j++)
59                 ;
60             if(dp[m][i+j]>dp[m][i-j])
61                 k=i+j;
62             else
63                 k=i-j;
64             printf("Jury #%d \nBest jury has value %d for prosecution and value %d for defence:\n",casenum,(k-base+dp[m][k])/2,(dp[m][k]-k+base)/2);
65             //把最终方案存在ans数组中
66             for(i=1;i<=m;i++)
67             {
68                 ans[i]=path[m-i+1][k];
69                 k-=minus[ans[i]];
70             }
71             qsort(ans+1,m,sizeof(int),compare);
72             for(i=1;i<=m;i++)
73                 printf(" %d",ans[i]);
74             printf("\n\n");
75     }
76     return 0;
77     
78 
79 
80 
81 }

转载于:https://www.cnblogs.com/pandy/archive/2008/11/26/1341106.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值