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