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

poj2400 – Supervisor, Supervisee

2012年07月14日 ⁄ 综合 ⁄ 共 2261字 ⁄ 字号 评论关闭

                            想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
                              转载请注明出处:
http://blog.csdn.net/wangjian8006

题目大意:
有n个老板和n个员工,他们对彼此有一个排名,现在要求选出最好的对应关系使他们平均分值最少

有n个老板和n个员工,首先给出有多少组测试数据,然后给出n
接下来n行,每行有n个数,第i行代表第i个老板对所有员工的喜好排名,排在第一个员工的标号的权值为0,第二个为-1,依次递减
再有n行,每行n个数,代表员工对老板的排名,排在第一个老板的标号的权值为0,第二个为-1,依次递减
这里权值为给对方所评的分数

这里要注意的是,题目的那个矩阵给反了,有可能是题目描述有问题,看discuss才知道的,否则会一直WA
将那个矩阵反过来输入试试就A了,我是将行看成老板,列看成员工的

找出最少平均分值之后,还要输出哪个老板和哪个员工匹配。如果有多个匹配,按字典序输出

解题思路:最少平均分值,用KM找出最佳匹配,使得权值和最小即可,当然他们的权值全为负数,所以当输出的时候要算出相反数

最少平均分值是等于最佳匹配的权值和除上一个总的点数2*n
找出了最少平均分值,最后那个匹配输出直接全排列找匹配,如果他们的权值和等于最佳匹配的权值和,就输出这种情况,直到全排列完即可。

/*
Memory 196K
Time   79MS
*/
#include <iostream>
using namespace std;
#define INF INT_MAX
#define MAXV 16
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)

int n,sum,cost;
int ly[MAXV],lx[MAXV],link[MAXV],tx[MAXV],ty[MAXV];
int map[MAXV][MAXV],mark[MAXV];

void init(){					//KM初始化
	int i,j;
	memset(link,-1,sizeof(link));
	cost=0;

	for(i=1;i<=n;i++) {ly[i]=0;lx[i]=map[i][1];}

	for(i=1;i<=n;i++){
		for(j=2;j<=n;j++)
			lx[i]=max(lx[i],map[i][j]);
	}
}

int hungary(int x){				//匈牙利找出完美匹配
	int i;
	tx[x]=1;
	for(i=1;i<=n;i++){
		if(!ty[i] && map[x][i]==lx[x]+ly[i]){
			ty[i]=1;
			if(link[i]==-1 || hungary(link[i])) {
				link[i]=x;
				return 1;
			}
		}
	}
	return false;
}

int km(){
	int i,tmp,j,k;
	init();

	for(i=1;i<=n;i++){
		while(1){
			memset(tx,0,sizeof(tx));
			memset(ty,0,sizeof(ty));

			if(hungary(i)) break;

			tmp=INF;
			for(j=1;j<=n;j++){
				if(tx[j]){
					for(k=1;k<=n;k++){
						if(!ty[k]){
							tmp=min(tmp,lx[j]+ly[k]-map[j][k]);
						}
					}
				}
			}

			for(j=1;j<=n;j++) {
                if(tx[j]) lx[j]-=tmp;
                if(ty[j]) ly[j]+=tmp;
            }
		}
	}
	for(i=1;i<=n;i++)
		if(link[i]!=-1) cost+=map[link[i]][i];

    return -cost;			//因为求出的最佳匹配的权值是负的,所以输出相反值
}

void dfs(int cap,int x){		//全排列搜索找出所有答案
	if(x<cost) return ;
	if(cap>n){
		if(x!=cost) return ;
		printf("Best Pairing %d\n",++sum);
		for(int i=1;i<=n;i++)
			printf("Supervisor %d with Employee %d\n",i,link[i]);
	}else{
		for(int i=1;i<=n;i++){
			if(!mark[i]){
				mark[i]=1;
				link[cap]=i;
				dfs(cap+1,x+map[cap][i]);
				mark[i]=0;
			}
		}
	}
}

int main(){
	int t,i,j,cnt,x;
	scanf("%d",&t);
	for(cnt=1;cnt<=t;cnt++){
		memset(map,0,sizeof(map));

		scanf("%d",&n);
		for(i=1;i<=n;i++){
			for(j=0;j<n;j++){
				scanf("%d",&x);
				map[x][i]-=j;
			}
		}

		for(i=1;i<=n;i++){
			for(j=0;j<n;j++){
				scanf("%d",&x);
				map[i][x]-=j;
			}
		}
		//平均差异是最佳匹配权值km()和除上总的点数2*n
		printf("Data Set %d, Best average difference: %.6lf\n",cnt,0.5*km()/n);

		sum=0;
		memset(mark,0,sizeof(mark));
		dfs(1,0);
		printf("\n");
	}
	return 0;
}

 

抱歉!评论已关闭.