POJ 2400 Supervisor, Supervisee(KM+DFS找相同最佳匹配)
专门去找了图论的题目,最近就在这上面下功夫了,虽然学长把DP讲了,不过似乎没那么多的时间去攻克,一个个来吧。做事不急才好啊!今天做这题挺有成就感的,POJ上A掉得才405个,感觉不错;
这题初看感觉很复杂,各种输出,其实主要思想可以转换成找最小匹配,一边是员工,一边是老板(可以这么理解),好老板喜欢好员工,好员工喜欢好老板,所以有了相互的评价,就是题目给的,那就用KM找最小匹配!找最小匹配的话就把相互的评价带成负值,最后算总值再加个负号就行了!
里面的“Best average difference” 其实就是员工的总评价除以2*n(人数,因为是双方,你懂得),一次KM得到的值作为对比,进行一次DFS找边,替换一条rank中已经找到的边,看是否能找到答案相同的匹配方案,然后输出就可;
#include <iostream>
#include <stdio.h>
using namespace std;
#define NN 20
int map[NN][NN];
int n,lack;
bool visx[NN],visy[NN];
int dx[NN],dy[NN];
int rank[NN];
int sum;
double ans;
bool flag[NN];
bool DFS(int v)
{
visx[v]=true;;
int i;
for(i=1;i<=n;i++)
{
if(visy[i])
continue;
int t=dx[v]+dy[i]-map[v][i];
if(!t)
{
visy[i]=true;
if(rank[i]==-1||DFS(rank[i]))
{
rank[i]=v;
return true;
}
}
else
if(lack>t)
lack=t;
}
return false;
}
double KM()
{
memset(dx,0,sizeof(dx));
memset(dy,0,sizeof(dy));
memset(rank,-1,sizeof(rank));
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(dx[i]<map[i][j])
dx[i]=map[i][j];
for(i=1;i<=n;i++)
{
while(true)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
lack=0xfffff;
if(DFS(i))
break;
for(j=1;j<=n;j++)
{
if(visx[j])
dx[j]-=lack;
if(visy[j])
dy[j]+=lack;
}
}
}
ans=0;
for(i=1;i<=n;i++)
ans+=-map[rank[i]][i];//值变为正的
return 1.0*ans/(2*n);//那个平均值求法在这
}//以上都是模板 没什么变化
void KM_DFS(int left,int dx)
{
int i,j;
if(left<0)
return ;
if(left==0)
{
if(dx==n+1) //满足条件输出
{
printf("Best Pairing %d\n",sum++);
for(i=1;i<=n;i++)
{
printf("Supervisor %d with Employee %d\n",i,rank[i]);
}
}
return ;
}
for(j=1;j<=n;j++) //替换一个已找到边
if(!flag[j])
{
flag[j]=true;
rank[dx]=j;
KM_DFS(left+map[dx][j],dx+1);
flag[j]=false;
}
}
int main()
{
int t,m,i,j;
scanf("%d",&t);
int k=1;
while(t--)
{
memset(map,0,sizeof(map));
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&m);
map[m][i]-=j;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&m);
map[i][m]-=j;
}
double mu=KM();
int p=2;
printf("Data Set %d, Best average difference: %.6lf\n",k++,mu-1);
sum=1;
memset(flag,false,sizeof(flag));
KM_DFS(ans,1);
printf("\n");
}
return 0;
}
浙公网安备 33010602011771号