POJ1015
Posted Blogggggg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1015相关的知识,希望对你有一定的参考价值。
题目链接:http://poj.org/problem?id=1015
大概题意:
法庭要挑选m人陪审团。先随机挑选n个公民,对于每个公民,控辩双方都有各自的“喜好度”p[ ] 和 d[ ],法庭要尽量保证陪审团的m人中控方总喜好度和辩方总喜好度的差值的绝对值尽可能小,如果最佳的结果有多个,那么就选择控辩双方总喜好度最高的那个。
解题思路:
日常不会dp题,哭),。。。
设一个二维数组 dp[i][j], i代表“使用”了几个人,j代表控辩双方喜好度之差,为了避免出现数组下标为负的情况,我们可以把j值的最后再加上20*m。
状态转移方程:dp[i+1][j+dat] = min(dp[i+1][j+dat] , dp[i][j]+sum).具体细节看代码吧。
Waring: 要把选取哪个人这个循环放在最外层,不然会出现这种bug: 比如说 dp[5][?] = {1,2,3,5,6} = {1,2,3,7,8},但是最优解是dp[6][?]={1,2,3,5,6,7}, 如果程序选取的是{1,2,3,5,6}..............待续
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 const int inf=0x7ffffff; 8 int dp[22][808]; 9 pair<int,int> pd[202]; 10 vector<int> path[22][808]; 11 int main() 12 { 13 // freopen("in.txt","r",stdin); 14 // freopen("out.txt","w",stdout); 15 int n,m,a,b,cases=1,min_n; 16 while(scanf("%d%d",&n,&m)==2&&n&&m){ 17 for(int i=1;i<=n;i++) 18 scanf("%d%d",&pd[i].first,&pd[i].second); 19 min_n=20*m; 20 for(int i=0;i<=m;i++){ 21 for(int j=0;j<=40*m;j++){ 22 path[i][j].clear(); 23 dp[i][j]=-inf; 24 } 25 } 26 dp[0][min_n]=0; 27 for(int k=1;k<=n;k++){ 28 int dat=pd[k].first-pd[k].second, sum=pd[k].first+pd[k].second; 29 for(int i=m-1;i>=0;i--){ 30 for(int j=0;j<=40*m;j++){ 31 if(dp[i][j]>=0){ 32 if(dp[i+1][j+dat]<=dp[i][j]+sum){ 33 dp[i+1][j+dat]=dp[i][j]+sum; 34 path[i+1][j+dat]=path[i][j]; 35 path[i+1][j+dat].push_back(k); 36 } 37 } 38 } 39 } 40 } 41 a=b=0; 42 for(int i=0;i<=20*m;i++){ 43 if(dp[m][min_n+i]>=0||dp[m][min_n-i]>=0){ 44 int temp; 45 if(dp[m][min_n+i]>dp[m][min_n-i]) temp=min_n+i; 46 else temp=min_n-i; 47 for(int l=0;l<m;l++){ 48 int ind=path[m][temp][l]; 49 a+=pd[ind].first,b+=pd[ind].second; 50 } 51 printf("Jury #%d\n",cases++); 52 printf("Best jury has value %d for prosecution and value %d for defence:\n",a,b); 53 for(int l=0;l<m;l++) printf(" %d",path[m][temp][l]); 54 printf("\n\n"); 55 break; 56 } 57 } 58 59 } 60 return 0; 61 }
以上是关于POJ1015的主要内容,如果未能解决你的问题,请参考以下文章