POJ 1015 Jury Compromise

本文介绍了一种使用状态压缩动态规划解决特定团队选择问题的方法。针对如何从大量候选人中选择固定人数的小团队,以使得团队能力值的绝对差最小,通过将问题转化为二维费用的0-1背包问题来解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚开始路径记录的时候用的状压,结果一直WA,然后对照官方数据,发现m虽然只有20,但n却是有200的

说多了都是泪啊,调了我好久

/*刚开始想了个递推方程,后来发现是不正确的-_-||因为这个方程不能保证无后效性。。。 
dp[k][i][j]:前k个人中,选中m个人,sumd-sump的值。
递推方程:dp[k][i][j]=max(dp[k][i-1][j-(d[i]-p[i])]);
重新看了一下背包九讲,发现这次再来看理解又深刻了不少:
这道题中,我们要做的是从100个中选20个出来,求其 |sumd-sump|最小,因为我们这里多了个绝对值,这使得我们如果按原来的思路,就不能保证无后效性。
因此,我们把计算出来的结果作为其一个费用,按问题转化为二维费用的问题,再按照0-1背包处理,就可以了 
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int p[205],d[205],n,m;
struct Jury{
	int val,path[21];
}dp[25][851];

void init(){
	int i,j;
	for(i=0;i<=24;i++){
		for(j=0;j<=821;j++){
			dp[i][j].val=-1;
			for(int k=0;k<21;k++) dp[i][j].path[k]=0;
		} 
	}
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	int cas=1;
	while(scanf("%d%d",&n,&m)){
		if(n==0 && m==0 ) break;
		memset(d,0,sizeof(d));
		memset(p,0,sizeof(p));
		int i,j,k;
		for(i=1;i<=n;i++) scanf("%d%d",&p[i],&d[i]);
		init();
		int fix=20*m;
		dp[0][fix].val=0;
		for(k=1;k<=n;k++){
			
			for(i=m-1;i>=0;i--){//只能用一次,从后往前  
			
				for(j=0;j<2*fix;j++){//到达j分数时的情况,有标志位记录m了,所以不用在乎顺序 
				
					int tmp=j+(d[k]-p[k]);
					if(dp[i][j].val!=-1) {
						
						if(dp[i][j].val+p[k]+d[k]>dp[i+1][tmp].val) {
							dp[i+1][tmp].val=dp[i][j].val+p[k]+d[k];
							for(int l=0;l<21;l++) dp[i+1][tmp].path[l]=dp[i][j].path[l];
							dp[i+1][tmp].path[i+1]=k;
						}
					}
				}
			}
		}
		printf("Jury #%d\n",cas++);
		for(i=0;i<=2*fix;i++){
			if(dp[m][fix-i].val!=-1||dp[m][fix+i].val!=-1){
				int temp=i;
				if(dp[m][fix-i].val>dp[m][fix+i].val) temp=-temp;
				int tmp1=(dp[m][fix+temp].val+temp)/2;
				int tmp2=(dp[m][fix+temp].val-temp)/2;
				printf( "Best jury has value %d for prosecution and value %d for defence:\n", tmp2,tmp1);  
				for(j=1;j<=20;j++){
					if(dp[m][fix+temp].path[j]) printf(" %d",dp[m][fix+temp].path[j]);
				}
				printf("\n");
				break;
			}
		}
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值