转载来源:http://www.cnblogs.com/E-star/archive/2012/07/22/2603809.html
题意:
有n个管理员需要雇佣n个工作人员。 每个管理员对每个工作人员的评价不同,评价值(score)从0-n-1,0代表评价最高,n-1代表评价最低,(这样处理用KMq求解时才能出现0)同样,每个工作人员对每个管理员也有不同 的评价,评价值也是从0-n-1,0代表评价值最高,n-1代表最低。问n个管理员怎样选择n个工作人员可以使的每个人的平均评价值最小。即总的评价值 /(2*n)最小。如果存在多种最佳方案,则按照字典序输出每一种情况。
思路:
我们把N个管理员与N个员工分成两个点集,X,Y.管理员X[i]与员工Y[j]总的评价值为X[i]对Y[j]的评价值+Y[j]对X[i]的评价值。然后建图求最小权匹配即可。KM求完之后得到完备匹配,由于所有可能的匹配肯定在所得到的完备匹配的相等子图上,在其上dfs所有可能结果即可。
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-7
#define M 1000100
//#define LL __int64
#define LL long long
#define INF 0x3f3f3f3f
#define PI 3.1415926535898
const int maxn = 110;
using namespace std;
int link[maxn], w[110][110];
int lx[maxn], ly[maxn];//记录顶标;
int slack[maxn];
bool vtx[maxn], vty[maxn], vt[maxn];
int match[maxn];
int n, cnt;
char str[110][110];
bool dfs(int i)
{
int j;
vtx[i] = true;
for(j = 1; j <= n; j++)
{
if(vty[j]) continue;
int tmp = lx[i] + ly[j] - w[i][j];
if(tmp == 0)
{
vty[j] = true;
if(dfs(link[j]) || link[j] == -1)
{
link[j] = i;
return true;
}
}
else
slack[j] = min(tmp, slack[j]);
}
return false;
}
int KM()
{
for(int i = 1; i <= n; i++)
{
lx[i] = -INF;
for(int j = 1 ; j <= n; j++)
{
lx[i] = max(lx[i], w[i][j]);
}
}
memset(link , -1 , sizeof(link));
memset(ly , 0 , sizeof(ly));
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
slack[j] = INF;
while(1)
{
memset(vtx , false , sizeof(vtx));
memset(vty , false , sizeof(vty));
if(dfs(i))
break;
int d = INF;
for(int j = 1; j <= n; j++)
{
if(!vty[j] && d > slack[j])
d = slack[j];
}
if(d == INF) return -1;
for(int j = 1; j <= n; j++)
if(vtx[j])
lx[j] -= d;
for(int j = 1; j <= n; j++)
{
if(vty[j])
ly[j] += d;
else
slack[j] -= d;
}
}
}
int sum = 0;
for(int i = 1; i <= n; i++)
{
if(link[i] > -1)
sum -= w[link[i]][i];
}
return sum;
}
void DfsRes(int i)
{
if (i > n)
{
printf("Best Pairing %d\n",cnt++);
for (i = 1; i <= n; ++i)
{
printf("Supervisor %d with Employee %d\n",i,match[i]);
}
}
for (int j = 1; j <= n; ++j)
{
if (lx[i] + ly[j] == w[i][j] && !vt[j])
{
vt[j] = true;
match[i] = j;
DfsRes(i + 1);
vt[j] = false;
}
}
}
int main()
{
int _case = 1;
int t;
cin >>t;
while(t--)
{
cin >>n;
memset(w , 0 , sizeof(w));
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < n; j++)
{
int k;
cin >>k;
w[k][i] -= j;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < n; j++)
{
int k;
cin >>k;
w[i][k] -= j;
}
}
printf("Data Set %d, Best average difference: %.6lf\n",_case++,KM()/(2.0*n));
cnt = 1;
DfsRes(1);
cout<<endl;
}
return 0;
}