poj1015(dp输出路径)

链接:点击打开链接

题意:有n个人,每个人有一个D值和P值,求选出m个人,使得|∑(D)-∑(P)|最小,如果最小值相同,则选择|∑(D)+∑(P)|较大的,输出选出的人和∑(D),∑(P)

代码:

#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
vector<int> path[8005][25];
int a[205],b[205];
int dp[8005][25],sum[8005][25];
int main(){
    int n,m,i,j,k,p,cas,tmp;
    int ansa,ansb,tmpa,tmpb;
    cas=1;
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        for(i=0;i<=40*n;i++)
        for(j=0;j<=m;j++)
        path[i][j].clear();
        for(i=1;i<=n;i++)
        scanf("%d%d",&a[i],&b[i]);
        dp[0][0]=1;                             //dp[i][j]表示能否用j个数,使得差值和为i
        for(i=1;i<=n;i++){                      //sum[i][j]表示j个数,差值是i时和的最大值
            tmp=a[i]-b[i]+20;                   //因为是求绝对值最小,因此需要将所有数加上
            for(j=40*m;j>=tmp;j--){             //20避免出现负数
                for(k=m;k>=1;k--){
                    if(!dp[j-tmp][k-1])
                    continue;
                    if(!dp[j][k]){              //看dp[j][k]是否被询问过
                        sum[j][k]=sum[j-tmp][k-1]+a[i]+b[i];
                        path[j][k]=path[j-tmp][k-1];
                        path[j][k].push_back(i);
                        dp[j][k]=1;
                    }
                    else if(sum[j][k]<sum[j-tmp][k-1]+a[i]+b[i]){
                        sum[j][k]=sum[j-tmp][k-1]+a[i]+b[i];
                        path[j][k]=path[j-tmp][k-1];
                        path[j][k].push_back(i);
                    }                           //path记录路径
                }
            }
        }
        p=0;                                    //正常要找0上下最小的,现在因为每个数
        while(!dp[20*m-p][m]&&!dp[20*m+p][m])   //都加上20,所以找20*m上下的
        p++;
        if(!dp[20*m+p][m]){
            ansa=abs(-p+sum[20*m-p][m])/2;      //已知a+b和a-b求a和b
            ansb=(sum[20*m-p][m]+p)/2;          //要注意正负号
            tmpa=20*m-p;
        }
        else if(!dp[20*m-p][m]){
            ansa=abs(p+sum[20*m+p][m])/2;
            ansb=(sum[20*m+p][m]-p)/2;
            tmpa=20*m+p;
        }
        else{
            if(sum[20*m+p][m]>sum[20*m-p][m]){
            ansa=abs(p+sum[20*m+p][m])/2;
            ansb=(sum[20*m+p][m]-p)/2;
            tmpa=20*m+p;
            }
            else{
            ansa=abs(-p+sum[20*m-p][m])/2;
            ansb=(sum[20*m-p][m]+p)/2;
            tmpa=20*m-p;
            }
        }
        printf("Jury #%d\n",cas++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n",ansa,ansb);
        for(i=0;i<path[tmpa][m].size();i++)
        printf(" %d",path[tmpa][m][i]);
        printf("\n\n");
    }
    return 0;
}


 

你可能感兴趣的:(源码,ACM,图论)