首页 > 其他 > 详细

POJ 1015 陪审团问题

时间:2019-07-28 11:05:19      阅读:65      评论:0      收藏:0      [点我收藏+]

题意略。

思路:

这个题目开始我本来打算用个二维dp,令dp[ i ][ j ]为考虑前i个人,有j个名额的时候,我所能获取的最小差,后来发现不好转移。因为dp[ i ][ j ]有可能是+2,

也有可能是-2,这两种值对我以后的求解可能都有用。后来想再添加一维,dp[ i ][ j ][ 0 ]表示正值的最小,dp[ i ][ j ][ 1 ]表示负值的最小(绝对值的最小)。

这样dp逻辑又很复杂。最后参考了网上的解法,于是将状态定义为:

dp[ i ][ j ][ k ]表示在前i个人里考虑,有j个名额,使得sigma(p) - sigma(d)为k时,我所能获得的sigma(p + d)的最大值。

状态转移方程:dp[ i ][ j ][ k ] = max(dp[i - 1][ j ][ k ] , dp[i - 1][j - 1][k - p[i] + d[i] ] + p[ i ] + d[ i ])

只可惜我做题时只想到了正负值的问题,没有更进一步将正负值直接确定为差值,然后dp对象为p + d,从而满足题目中的第二个条件。

有时dp对象可以是次要条件,而不是首要条件,换一种方向去思考问题。

内存很紧张

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn1 = 25;
const int maxn2 = 205;
const int maxn3 = 805;
const int mid = maxn3>>1;
const int F = 0x3f;
const int INF = 0x3f3f3f3f;

struct node{
    int peo,place,sub;
    node(int peo = 0,int place = 0,int sub = 0){
        this->peo = peo,this->place = place,this->sub = sub;
    }
};

int p[maxn2],d[maxn2],dp[maxn2][maxn1][maxn3],store[maxn2],n,m;
node path[maxn2][maxn1][maxn3];

int main(){
    int cas = 1;
    while(scanf("%d%d",&n,&m) == 2 && (n + m)){
        for(int i = 1;i <= n;++i) scanf("%d%d",&p[i],&d[i]);
        int total = 20 * m;
        int low = mid - total,up = mid + total;
        
        for(int i = 0;i <= n;++i){
            for(int j = 0;j <= m;++j){
                for(int k = low;k <= up;++k){
                    dp[i][j][k] = -1;
                    path[i][j][k] = node(-1,-1,-1);
                }
            }
        }
        
        for(int i = 0;i <= n;++i) dp[i][0][mid] = 0;
        
        for(int i = 1;i <= n;++i){
            int bound = min(i,m);
            for(int j = 1;j <= bound;++j){
                for(int k = low;k <= up;++k){
                    int part1 = dp[i - 1][j][k];
                    int part2 = (k - p[i] + d[i] < low || k - p[i] + d[i] > up || dp[i - 1][j - 1][k - p[i] + d[i]] == -1) ? -1 : dp[i - 1][j - 1][k - p[i] + d[i]] + p[i] + d[i];
                    dp[i][j][k] = max(part1,part2);                    
                    if(part1 == -1 && part2 == -1) continue;
                    if(part1 > part2) path[i][j][k] = node(i - 1,j,k);
                    else path[i][j][k] = node(i - 1,j - 1,k - p[i] + d[i]);
                }
            }
        }
        int idx;
        for(int i = 0;i <= total;++i){
            int lft = mid - i,rht = mid + i;
            int maxx = max(dp[n][m][lft],dp[n][m][rht]);
            if(maxx == -1) continue;
            if(maxx == dp[n][m][lft]) idx = lft;
            else idx = rht;
            if(maxx != -1) break;
        }
        int tail = 0;
        for(int i = n,j = m,k = idx;i != -1;){
            node temp = path[i][j][k];
            int nxti = temp.peo;
            int nxtj = temp.place;
            int nxtk = temp.sub;
            if(nxti == -1) break;
            if(nxtj < j) store[tail++] = i;
            i = nxti,j = nxtj,k = nxtk;
        }
        int ans1 = 0,ans2 = 0;
        for(int i = 0;i < tail;++i){
            ans1 += p[store[i]];
            ans2 += d[store[i]];
        }
        printf("Jury #%d\n",cas++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n",ans1,ans2);
        for(int i = tail - 1;i >= 0;--i) printf(" %d",store[i]);
        printf("\n\n");
    }
    return 0;
}

/*
4 2 
1 2 
2 3 
4 1 
6 2 
 
10 5  
3  8 
15  8 
11  8 
7  8 
1  8 
17  8
8  8
2  8
13  8
3  8

5 3  
13 11
3 17
15 20
6 13
17  9

8 5   
 3  5
17 16
 6  0
17 10
 6 14
 3 19
 4 13
 0 17
*/

 

POJ 1015 陪审团问题

原文:https://www.cnblogs.com/tiberius/p/11257907.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!