Poj--1015(DP,状态搜索)

2014-11-28 22:00:10

思路:这题在需要记录状态,一开始没有记录状态瞎搞QAQ。

  用dp[i][j]表示选择了i个人,且差值为j时的最优解(即:sigma(p) + sigma(q) 最大)

  然后以i做最外层循环枚举,dp[i][j] = max(dp[i - 1][j - (p[k] - q[k])] (1 <= k <= n)

  当然在转移时我们得知道dp[i - 1][j - (p[k] - q[k])]中是否已经选了k,其实我们可以用path[i][j]来存储dp[i][j]最后一个取的人,然后dp[i - 1][j - (p[path[i][j]] - q[path[i][j]]),这样一步一步搜索回去看看是否已经选了k

  1 /*************************************************************************
  2     > File Name: p1015.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com 
  5     > Created Time: Fri 28 Nov 2014 07:22:40 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <stack>
 16 #include <queue>
 17 #include <iostream>
 18 #include <algorithm>
 19 using namespace std;
 20 #define lp (p << 1)
 21 #define rp (p << 1|1)
 22 #define getmid(l,r) (l + (r - l) / 2)
 23 #define MP(a,b) make_pair(a,b)
 24 typedef long long ll;
 25 const int INF = 1 << 30;
 26 
 27 int n,m;
 28 int dp[30][810];
 29 int p[210],q[210];
 30 int path[30][810];
 31 int ans[30],cnt;
 32 
 33 void Print(int a,int b){
 34     int k = path[a][b];
 35     int deta = p[k] - q[k];
 36     if(a > 1)
 37         Print(a - 1,b - deta);
 38     ans[++cnt] = k;
 39 }
 40 
 41 bool Judge(int a,int b,int cur){
 42     while(a >= 1){
 43         int k = path[a][b];
 44         int deta = p[k] - q[k];
 45         if(k == cur)
 46             return false;
 47         a = a - 1;
 48         b = b - deta;
 49     }
 50     return true;
 51 }
 52 
 53 int main(){
 54     int Case = 0;
 55     while(scanf("%d%d",&n,&m) != EOF){
 56         if(n == 0 && m == 0)
 57             break;
 58         for(int i = 1; i <= n; ++i){
 59             scanf("%d%d",p + i,q + i);
 60         }
 61         memset(path,0,sizeof(path));
 62         memset(dp,-1,sizeof(dp));
 63         dp[0][400] = 0;
 64         for(int i = 1; i <= m; ++i){
 65             for(int j = 0; j <= 800; ++j){
 66                 for(int k = 1; k <= n; ++k){
 67                     int deta = p[k] - q[k];
 68                     if(j - deta < 0 || j - deta > 800 || dp[i - 1][j - deta] == -1
 69                             || !Judge(i - 1,j - deta,k))
 70                         continue;
 71                     if(dp[i - 1][j - deta] + p[k] + q[k] > dp[i][j]){
 72                         dp[i][j] = dp[i - 1][j - deta] + p[k] + q[k];
 73                         path[i][j] = k;
 74                     }
 75                 }
 76             }
 77         }
 78         int tmin = INF,sum,flag;
 79         for(int j = 400; j <= 800; ++j){
 80             if(dp[m][j] != -1){
 81                 tmin = j - 400;
 82                 sum = dp[m][j];
 83                 flag = j;
 84                 break;
 85             }
 86         }
 87         for(int j = 400; j >= 0; --j){
 88             if(dp[m][j] != -1){
 89                 if(400 - j < tmin || (400 - j == tmin && dp[m][j] > sum)){
 90                     tmin = 400 - j;
 91                     sum = dp[m][j];
 92                     flag = j;
 93                     break;
 94                 }
 95             }
 96         }
 97         printf("Jury #%d \n",++Case);
 98         int base = (sum - tmin) / 2;
 99         printf("Best jury has value %d for prosecution and value %d for defence:\n",
100                 flag >= 400 ? base + tmin : base,flag >= 400 ? base : base + tmin);
101         cnt = 0;
102         Print(m,flag);
103         sort(ans + 1,ans + cnt + 1);
104         for(int i = 1; i <= cnt; ++i)
105             printf(" %d",ans[i]);
106         printf("\n\n");
107     }
108     return 0;
109 }

 

posted @ 2014-11-28 23:05  Naturain  阅读(112)  评论(0编辑  收藏  举报