**POJ1015.Jury Compromise(01背包变形+二维背包)

题目链接:http://poj.org/problem?id=1015
题意:n个评审团人数,从中选出m个人,要求这m个人的D(J)-P(J)绝对值最小,D(J)=SUM(Di),P(J)=SUM(Pi),当存在相同D(J)-P(J)时,输出D(J)+P(J)最大的情况。
解题思路:因为D(J)-P(J)有正有负,所以起点从修正值20*m开始,20为D-P最大的可能值,dp[i][j]表示选择i个人,D-P值为j+20m时最大的D+P值。
利用path[i][j]表示i个人,D-P值为j时候选择了的方案
模拟01背包,背包容量为m,每个人的重量为1
初始化dp[0][20
m]=0,然后进行二维01背包操作

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n,m;
int t;
int dp[25][810];
struct node{
	int p,d;
	int add;
	int sub;
}a[220];
vector<int> path[25][810];
int main(){
	while(cin>>n>>m){
		t++;
		if(n==0&&m==0) break;
		memset(dp,-1,sizeof(dp));
		for(int i=1;i<=m;i++)
			for(int j=0;j<810;j++)
				path[i][j].clear();
	    for(int i=1;i<=n;i++){
		   scanf("%d%d",&a[i].p,&a[i].d);
		   a[i].add=a[i].p+a[i].d;
		   a[i].sub=a[i].d-a[i].p;
		}
		int mid=20*m;
		dp[0][mid]=0;
	    for(int i=1;i<=n;i++){
			for(int j=m-1;j>=0;j--){   //模拟01背包问题,每个人只能取一次
				for(int k=0;k<=2*mid;k++){   //处理二维背包第二维
					if(dp[j][k]>=0){
						if(dp[j][k]+a[i].add>dp[j+1][k+a[i].sub]){
							dp[j+1][k+a[i].sub]=dp[j][k]+a[i].add;
							//转移评审团方案
							path[j+1][k+a[i].sub]=path[j][k];   
						    //放入新选入的人
							path[j+1][k+a[i].sub].push_back(i);
						}
					}
				}
			}
		}
		int ans;
		for(int i=0;i<=mid;i++){
			if(dp[m][mid-i]>=0||dp[m][mid+i]>=0){
				ans=i;
				break;
			}
		}
		int res=dp[m][mid-ans]>=dp[m][mid+ans]? mid-ans: mid+ans;
		int d=(res-mid+dp[m][res])/2;
		int p=(dp[m][res]-res+mid)/2;
		int len=path[m][res].size();
		printf("Jury #%d\n",t);
		printf("Best jury has value %d for prosecution and value %d for defence: \n",p,d);
		for(int i=0;i<len;i++){
			printf("%d ",path[m][res][i]);
		}
		printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/107247003