POJ 1015

116 篇文章 2 订阅
35 篇文章 0 订阅

这道题应该来说,比较难,特别是变量的下标 有点多 且比较复杂。

题目的意思是:

给出n组数,每组数有一个P[i],D[i], 求出其中的m组,使得sum(P[i])-sum(D[i])绝对值最大,如果有多个这样的值,取其中sum(P[i])+sum(D[i])最大的一组


分析:算法思想,动态规划

用 V(i) 表示第i组的辩控差

用S(i) 表示第i组的辩控和

用f(j,k) 表示取j个人,辩控差为k的方案的最大的辩控和

Path[i][j]表示最后加进来的那个人

状态转化方程:

f[i+1][j+P[k]-D[k]] = f[i][j] + P[k] + D[k], 要求k之前没有选过

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;

int f[30][1000];//f[j][k]表示取j个候选人,辩控差为k的方案中
//辩控和最大的那个方案
int Path[30][1000];
//记录了最后一个候选人的编号
int P[300];
int D[300];
int Answer[30]; //存放最终方案的人选

bool cmp(int a,int b){
    if(a<b)
        return true;
    else
        return false;
}

int main(){
    int i,j,k;
    int t1,t2;
    int n,m;
    int nMinP_D;
    int iCase;    //测试编号
    iCase = 0;
    while(scanf("%d %d",&n,&m)){
        if(n==0 && m==0)    break;
        iCase++;
        for(i=1;i<=n;i++){
            scanf("%d %d",&P[i],&D[i]);
        }
        memset(f,-1,sizeof(f));
        memset(Path,0,sizeof(Path));
        nMinP_D = m*20;
        f[0][nMinP_D] = 0;
        for(j=0;j<m;j++){
            for(k=0;k<=nMinP_D*2;k++){
                if(f[j][k]>=0){
                    for(i=1;i<=n;i++){
                        if(f[j][k]+P[i]+D[i]>f[j+1][k+P[i]-D[i]]){
                                t1 = j;
                                t2 = k;
                                while(t1>0&&Path[t1][t2]!=i){    //排除掉选过的情况
                                        t2 -= P[Path[t1][t2]] - D[Path[t1][t2]];
                                        t1--;
                                }
                                if(t1 == 0){
                                        f[j+1][k+P[i]-D[i]] = f[j][k]+P[i]+D[i];
                                        Path[j+1][k+P[i]-D[i]] = i;
                                }
                        }
                    }
                }
            }
        }
                i = nMinP_D;
                j = 0;
                while(f[m][i+j]<0&&f[m][i-j]<0) j++;  //找到辩控差最小的情况
                if(f[m][i+j]>f[m][i-j]) k=i+j;
                else k=i-j;
                printf("Jury #%d\n",iCase);
                printf("Best jury has value %d for prosecution and value %d for defence:\n",(k+f[m][k]-nMinP_D)/2,(f[m][k]+nMinP_D-k)/2); //相当于解一个方程
                //x+y=f[m][k];x-y+MinP_D=k
                for(i=1;i<=m;i++){
                    Answer[i] = Path[m-i+1][k];
                    k -= P[Answer[i]] - D[Answer[i]]; //向上回溯解得 选中的 人
                }
                sort(Answer+1,Answer+m+1,cmp);
                for(i=1;i<=m;i++)
                printf(" %d",Answer[i]);
                printf("\n\n");
                                                    
    }
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值