POJ 1015 DP

题目链接:  http://poj.org/problem?id=1015

分析: (参考于: http://blog.csdn.net/lyy289065406/article/details/6671105 )

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <vector>
using namespace std;
const int inf = 0x7FFFFFFF;
const int maxn = 1000;
struct node{
    int p,d;
    void read(){
        scanf("%d%d",&p,&d);
    }
}f[205];

int cnt[25][805];   
int dp[25][805];    ///dp[j][k]表示 选j个,差为k(+400) 的最大和

void Init(){
    memset(cnt,0,sizeof(cnt));
    memset(dp,-1,sizeof(dp));
    dp[0][400]=0;   
}

bool Is_used(int i,int j,int k){  ///是否已选
    while(j&&cnt[j][k]!=i){
        int t=cnt[j][k];
        --j;
        k-=(f[t].p-f[t].d);
    }
    return j?true:false;
}

int main(){
    //freopen("C:\\Users\\DGP\\Desktop\\in.txt","r",stdin);
    //freopen("C:\\Users\\DGP\\Desktop\\out.txt","w",stdout);
    int n,m,cas=1;
    while(~scanf("%d%d",&n,&m),n+m){ if(cas>33)break;
        for(int i=1;i<=n;++i)
            f[i].read();
        Init();
        for(int j=1; j<=m; j++)
            for(int k=0; k<=800; k++)
                if(dp[j-1][k]>=0)  ///区间已平移,dp[0][fix]才是真正的dp[0][0]
                    for(int i=1; i<=n; i++) {
                        int c=f[i].p-f[i].d;
                        int s=f[i].p+f[i].d;
                        if(dp[j][k+c]<dp[j-1][k]+s)
                            if(!Is_used(i,j-1,k)){
                                dp[j][k+c]=dp[j-1][k]+s;
                                cnt[j][k+c]=i;
                            }
                    }
        int i=0;
        while(dp[m][400+i]==-1&&dp[m][400-i]==-1) ++i;
        int q=dp[m][400-i]>dp[m][400+i]?400-i:400+i;
        int a=(dp[m][q]+q-400)/2;
        int b=(dp[m][q]-q+400)/2;
        printf("Jury #%d\n",cas++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n",a,b);
        int h[20],t;
        i=0;
        while(cnt[m][q]){
            h[i++]=t=cnt[m][q];
            --m;
            q-=(f[t].p-f[t].d);
        }
        sort(h,h+i);
        for(int j=0;j<i;++j)
            printf(" %d",h[j]);
        puts("");
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值