现在的位置: 首页 > 综合 > 正文

poj1015 陪审团(dp)

2013年08月03日 ⁄ 综合 ⁄ 共 2052字 ⁄ 字号 评论关闭

        蛋碎的一题,刚开始觉得挺简单,摸过来就开始做了。设计状态是dp(n,m),代表前n个人里选m个时对应的最小的|D(J) - P(J)|,等做完提交发现不对,然后发现|D(J)-P(J)|这个压根不满足最优子结构啊,然后要全删了重做。

        后来参考了下discuss里的思路,写了三维的。dp(n,m,r)代表前n个里边选m个,使D(J)-P(J)==r,dp(n,m,r)记录此时的D(J)+P(J) 。这地方因为r有可能是负数,所以要先做一下处理了。具体的写法有点像背包。然后可以从r==0开始往数轴两边算,直到有一种方案可行,就找到当前最优的了。记路径也是挺麻烦的事,最后还是用的最笨的方法得到的路径。整了一个晚上,好在1A了。代码翔一样长啊。。。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int n,m;
int p[201];
int d[201];
int t[201];
int dt[201][21][801];
int path[201][21][801];
int parray[20];

int cmp(const void* x,const void* y){
	return *((int*)x)-*((int*)y);
}

int dp(int nn,int mm,int re){//前nn个里选mm个,使D(J) - P(J)==re
	if(dt[nn][mm][re]!=-1){
		return dt[nn][mm][re];
	}
	if(nn<mm||nn<0||mm<0){
		return -1;
	}
	if(mm==0){
		path[nn][mm][re]=-1;
		if(re==0){
			return 0;
		}
		return -2;
	}
	if(nn==mm){//恰好够
		int i;
		int s=0;
		int sp=0;
		for(i=0;i<nn;i++){//全选上试试行不行
			s+=t[i];
			sp+=(p[i]+d[i]);
		}
		if(s==re){//全选上恰好符合要求
			for(i=nn;i>0;i--){
				path[i][i][s]=i-1;//全选上
				s-=t[i-1];
			}
			dt[nn][mm][re]=sp;
			return sp;
		}
		dt[nn][mm][re]=-2;
		return -2;
	}
	//nn>mm
	int x=dp(nn-1,mm,re);//不选
	int y=dp(nn-1,mm-1,re-t[nn-1]);//选
	if(x==-2&&y==-2){//选或不选都走不通
		dt[nn][mm][re]=-2;
		return -2;
	}
	//至少有一个能走通
	if(x==-2){//“选” 走通
		y+=(p[nn-1]+d[nn-1]);
		dt[nn][mm][re]=y;
		path[nn][mm][re]=nn-1;
		return y;
	}
	if(y==-2){//“不选” 走通
		dt[nn][mm][re]=x;
		path[nn][mm][re]=-1;//-1代表不选
		return x;
	}
	//x!=-2&&y!=-2
	//走到这,说明选不选该点都能走通
	//那就继续根据和判断,挑选和较大的一个
	y+=(p[nn-1]+d[nn-1]);
	if(x<y){
		path[nn][mm][re]=nn-1;
		x=y;
	}else{
		path[nn][mm][re]=-1;
	}
	dt[nn][mm][re]=x;
	return x;
}

int main(void){
	int i,e,f,x,nn,mm;
	int j=1;
	while(1){
		scanf("%d %d",&n,&m);
		if(n==0&&m==0){
			break;
		}
		
		memset(dt,-1,sizeof(dt));//初始化
		memset(parray,-1,sizeof(parray));
		
		for(i=0;i<n;i++){
			scanf("%d %d",p+i,d+i);
			t[i]=p[i]+20-d[i];
		}
		
		x=20*m;
		for(i=0;i<=x;i++){
			e=dp(n,m,x+i);//以x为起始往两边找
			f=dp(n,m,x-i);
			if(e!=-2||f!=-2){
				break;
			}
		}
		
		i=e>f?i:-i;
		e=e>f?e:f;
		x+=i;
		printf("Jury #%d\n",j++);
		printf("Best jury has value %d for prosecution and value %d for defence:\n",(e+i)/2,(e-i)/2);
		
		f=0;
		nn=n;
		mm=m;
		for(i=0;i<n;i++){//顺着找路径
			e=path[nn][mm][x];
			if(e!=-1){//选择了某个点
				mm--;
				x-=t[nn-1];//扣除掉该点的信息
				parray[f++]=e;
			}
			nn--;//nn始终减1
		}
		qsort(parray,m,sizeof(int),cmp);
		for(i=0;i<m;i++){
			printf(" %d",parray[i]+1);
		}
		printf("\n\n");
	}
	return 0;
}

抱歉!评论已关闭.