想看更多的解题报告: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;
}