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;
	
	
}
posted @ 2011-08-15 21:31  Lxsec  阅读(517)  评论(0编辑  收藏  举报