POJ 2400 KM最小权匹配+输出所有匹配方案
2014-09-07 10:17
453 查看
Supervisor, Supervisee
Description
Suppose some supervisors each get to hire a new person for their department. There are N people to be placed in these N departments. Each supervisor interviews all N people, and ranks them according to how much she wants each of them in her department (1 being
"really want" and N being "really don't want"). In turn, each of the N candidates ranks each of the supervisors as to how much that person would like to work for that supervisor (again, 1 is "really want to work for him/her" and N is "really don't want to
work for him/her"). Given the scores that each supervisor has for each candidate, and the scores each candidate has for each manager, write a computer program to determine the "best match" of candidates to supervisors. The "best match" is determined by finding
the distribution that leads to the highest overall (i.e. sum of) satisfaction for all people. The closer a person is to her number one choice, the better. If everyone gets their number one choice, the average difference will be 0.
Input
The first line of the input will contain a single integer greater than 0 specifying the number of test cases.
The next line will contain a single integer value N, 0 < N < 15, representing the number of supervisors (and the number of employees - there are N supervisors and N employees). The next N lines will be the preferences of each of the N supervisors. Each line
will contain N integer entries (1 through N for employees 1 through N), each separated by a space character, that represents the preferences of that supervisor from most preferred to least preferred. More specifically, the first entry on the line will represent
that supervisor's first choice, the second entry her second, and so on. The next N lines will be the preferences of the N employees, in the same format as the supervisors.
All lines of data in the input file will end with an empty line.
Output
For each test case, write the test case number (starting with 1) followed by the best average difference written to six digits of precision to the right of the decimal point. On the next line, show which best match it was (starting with 1). On the next N lines,
show each supervisor (starting with 1) followed by the employee with which she was matched (1 per line). NOTE: if there is more than one best match, matches should be listed in ascending permuted order (see sample output).
Separate each data set with an empty line.
Sample Input
Sample Output
Source
Tehran 2003 Preliminary
分析:注意题目的两个矩阵输入交换了。。。先求出KM最小权值匹配,然后暴力dfs输出解即可。
代码:
//复杂度O(n^3)
//其实在求最大 最小的时候只要用一个模板就行了,把边的权值去相反数即可得到另外一个.求结果的时候再去相反数即可
//邻接矩阵特别需要注意重边的问题,切记
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll; //记得必要的时候改成无符号
const int maxn=20;
const int INF=1000000000;
int n,nx,ny;
int march[maxn],lx[maxn],ly[maxn],slack[maxn]; //lx,ly为顶标,nx,ny分别为x点集y点集的个数
int visx[maxn],visy[maxn],w[maxn][maxn];
int dfs(int x)
{
visx[x]=1;
for(int y=1;y<=ny;y++)
{
if(visy[y])
continue;
int t=lx[x]+ly[y]-w[x][y];
if(t==0)
{
visy[y]=1;
if(march[y]==-1||dfs(march[y]))
{
march[y]=x;
return 1;
}
}
else if(slack[y]>t) //不在相等子图中slack 取最小的
slack[y]=t;
}
return 0;
}
int KM()
{
int i,j;
memset(march,-1,sizeof(march));
memset(ly,0,sizeof(ly));
for(i=1;i<=nx;i++) //lx初始化为与它关联边中最大的
for(j=1,lx[i]=-INF;j<=ny;j++)
if(w[i][j]>lx[i])
lx[i]=w[i][j];
for(int x=1;x<=nx;x++)
{
for(i=1;i<=ny;i++)slack[i]=INF;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(x)) //若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
break; //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
//方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
//所有在增广轨中的Y方点的标号全部加上一个常数d
int d=INF;
for(i=1;i<=ny;i++)
if(!visy[i]&&d>slack[i])
d=slack[i];
for(i=1;i<=nx;i++)
if(visx[i])
lx[i]-=d;
for(i=1;i<=ny;i++) //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
if(visy[i])
ly[i]+=d;
else
slack[i]-=d;
}
}
int res=0;
for(i=1;i<=ny;i++)
if(march[i]>-1)
res+=w[march[i]][i];
return res;
}
int ans,chu[maxn],js;
bool use[maxn];
void out()
{
printf("Best Pairing %d\n",++js);
for(int i=1;i<=n;i++)
printf("Supervisor %d with Employee %d\n",i,chu[i]);
}
void solve(int x,int sum)
{
if(sum<ans)return;
if(x==n+1){
out();
return;
}
for(int i=1;i<=n;i++){
if(use[i]==0){
use[i]=1;
chu[x]=i;
solve(x+1,sum+w[x][i]);
use[i]=0;
}
}
}
int main ()
{
int i,j,x,T;
scanf("%d",&T);
for(int l=1;l<=T;l++){
scanf("%d",&n);
nx=ny=n;
memset(w,0,sizeof(w));
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&x);
w[x][i]-=j-1;
}
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&x);
w[i][x]-=j-1;
}
}
ans=KM();
memset(use,0,sizeof(use));
printf("Data Set %d, Best average difference: %.6f\n",l,-ans*0.5/n);
js=0;
solve(1,0);
printf("\n");
}
return 0;
}
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2407 | Accepted: 681 |
Suppose some supervisors each get to hire a new person for their department. There are N people to be placed in these N departments. Each supervisor interviews all N people, and ranks them according to how much she wants each of them in her department (1 being
"really want" and N being "really don't want"). In turn, each of the N candidates ranks each of the supervisors as to how much that person would like to work for that supervisor (again, 1 is "really want to work for him/her" and N is "really don't want to
work for him/her"). Given the scores that each supervisor has for each candidate, and the scores each candidate has for each manager, write a computer program to determine the "best match" of candidates to supervisors. The "best match" is determined by finding
the distribution that leads to the highest overall (i.e. sum of) satisfaction for all people. The closer a person is to her number one choice, the better. If everyone gets their number one choice, the average difference will be 0.
Input
The first line of the input will contain a single integer greater than 0 specifying the number of test cases.
The next line will contain a single integer value N, 0 < N < 15, representing the number of supervisors (and the number of employees - there are N supervisors and N employees). The next N lines will be the preferences of each of the N supervisors. Each line
will contain N integer entries (1 through N for employees 1 through N), each separated by a space character, that represents the preferences of that supervisor from most preferred to least preferred. More specifically, the first entry on the line will represent
that supervisor's first choice, the second entry her second, and so on. The next N lines will be the preferences of the N employees, in the same format as the supervisors.
All lines of data in the input file will end with an empty line.
Output
For each test case, write the test case number (starting with 1) followed by the best average difference written to six digits of precision to the right of the decimal point. On the next line, show which best match it was (starting with 1). On the next N lines,
show each supervisor (starting with 1) followed by the employee with which she was matched (1 per line). NOTE: if there is more than one best match, matches should be listed in ascending permuted order (see sample output).
Separate each data set with an empty line.
Sample Input
2 7 1 2 3 4 5 6 7 2 1 3 4 5 6 7 3 1 2 4 5 6 7 4 1 2 3 5 6 7 5 1 2 3 4 6 7 6 1 2 3 4 5 7 7 1 2 3 4 5 6 1 2 3 4 5 6 7 2 1 3 4 5 6 7 3 1 2 4 5 6 7 4 1 2 3 5 6 7 5 1 2 3 4 6 7 6 1 2 3 4 5 7 7 1 2 3 4 5 6 2 1 2 2 1 1 2 1 2
Sample Output
Data Set 1, Best average difference: 0.000000 Best Pairing 1 Supervisor 1 with Employee 1 Supervisor 2 with Employee 2 Supervisor 3 with Employee 3 Supervisor 4 with Employee 4 Supervisor 5 with Employee 5 Supervisor 6 with Employee 6 Supervisor 7 with Employee 7 Data Set 2, Best average difference: 0.250000 Best Pairing 1 Supervisor 1 with Employee 1 Supervisor 2 with Employee 2
Source
Tehran 2003 Preliminary
分析:注意题目的两个矩阵输入交换了。。。先求出KM最小权值匹配,然后暴力dfs输出解即可。
代码:
//复杂度O(n^3)
//其实在求最大 最小的时候只要用一个模板就行了,把边的权值去相反数即可得到另外一个.求结果的时候再去相反数即可
//邻接矩阵特别需要注意重边的问题,切记
#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll; //记得必要的时候改成无符号
const int maxn=20;
const int INF=1000000000;
int n,nx,ny;
int march[maxn],lx[maxn],ly[maxn],slack[maxn]; //lx,ly为顶标,nx,ny分别为x点集y点集的个数
int visx[maxn],visy[maxn],w[maxn][maxn];
int dfs(int x)
{
visx[x]=1;
for(int y=1;y<=ny;y++)
{
if(visy[y])
continue;
int t=lx[x]+ly[y]-w[x][y];
if(t==0)
{
visy[y]=1;
if(march[y]==-1||dfs(march[y]))
{
march[y]=x;
return 1;
}
}
else if(slack[y]>t) //不在相等子图中slack 取最小的
slack[y]=t;
}
return 0;
}
int KM()
{
int i,j;
memset(march,-1,sizeof(march));
memset(ly,0,sizeof(ly));
for(i=1;i<=nx;i++) //lx初始化为与它关联边中最大的
for(j=1,lx[i]=-INF;j<=ny;j++)
if(w[i][j]>lx[i])
lx[i]=w[i][j];
for(int x=1;x<=nx;x++)
{
for(i=1;i<=ny;i++)slack[i]=INF;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(x)) //若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
break; //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
//方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
//所有在增广轨中的Y方点的标号全部加上一个常数d
int d=INF;
for(i=1;i<=ny;i++)
if(!visy[i]&&d>slack[i])
d=slack[i];
for(i=1;i<=nx;i++)
if(visx[i])
lx[i]-=d;
for(i=1;i<=ny;i++) //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
if(visy[i])
ly[i]+=d;
else
slack[i]-=d;
}
}
int res=0;
for(i=1;i<=ny;i++)
if(march[i]>-1)
res+=w[march[i]][i];
return res;
}
int ans,chu[maxn],js;
bool use[maxn];
void out()
{
printf("Best Pairing %d\n",++js);
for(int i=1;i<=n;i++)
printf("Supervisor %d with Employee %d\n",i,chu[i]);
}
void solve(int x,int sum)
{
if(sum<ans)return;
if(x==n+1){
out();
return;
}
for(int i=1;i<=n;i++){
if(use[i]==0){
use[i]=1;
chu[x]=i;
solve(x+1,sum+w[x][i]);
use[i]=0;
}
}
}
int main ()
{
int i,j,x,T;
scanf("%d",&T);
for(int l=1;l<=T;l++){
scanf("%d",&n);
nx=ny=n;
memset(w,0,sizeof(w));
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&x);
w[x][i]-=j-1;
}
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&x);
w[i][x]-=j-1;
}
}
ans=KM();
memset(use,0,sizeof(use));
printf("Data Set %d, Best average difference: %.6f\n",l,-ans*0.5/n);
js=0;
solve(1,0);
printf("\n");
}
return 0;
}
相关文章推荐
- POJ 2400 KM最小权匹配+输出所有配对方案
- POJ 2400 KM算法 最小权匹配 回溯输出所有最优匹配方案
- 【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)
- 【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)
- 二分图最大匹配 输出字典序最小的方案 poj 3715
- 二分图完备匹配(最小费用 || KM) poj 2195 GoingHome
- POJ 3686 —— 最小费用流||最小费用匹配&KM
- Poj(3686),最小权匹配,多重匹配,KM
- POJ-2400 Supervisor, Supervisee 带权值匹配+枚举所有匹配情况
- poj 3686 The Windy's 二分图最小权和匹配KM
- poj 2195(KM求最小权匹配)
- poj 2195(KM求最小权匹配)
- POJ 2400 最小权匹配
- POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)
- poj 1734 Sightseeing trip(floyd求最小环并输出方案)
- poj 2400 Supervisor, Supervisee KM求二分图+dfs输出所有解
- POJ 2400 最小权匹配
- POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)
- poj 2125 Destroying The Graph 最小割+方案输出
- POJ 2400 Supervisor, Supervisee(KM+DFS找相同最佳匹配)