pku 2400

来源:互联网 发布:caffe能做什么用 编辑:程序博客网 时间:2024/06/05 05:27

题意:求最小权匹配的所有匹配方案

分析:用km()算法求得最小匹配后,对于所有的 lx[i] + ly[[j] = g[i][j]  的 i ,j 建边 i---->j。然后求新建图的所有完美匹配(dfs即可)

代码:

#include<stdio.h>#include<string.h>#define N 20#define inf 1000000000int lx[N],ly[N],vx[N],vy[N],x[N],y[N];int g[N][N],slack[N];char map[N][N];int a[N][N],b[N][N];int m,n,num;int search(int u){int v;vx[u]=1;for(v=1;v<=n;v++){if(vy[v]) continue;if(lx[u]+ly[v]==g[u][v]){vy[v]=1;if(y[v]==-1||search(y[v])){x[u]=v;y[v]=u;return 1;}}else if(lx[u]+ly[v]-g[u][v]<slack[v])slack[v]=lx[u]+ly[v]-g[u][v];}return 0;}int KM(){int i,j,min,ans;memset(ly,0,sizeof(ly));memset(x,-1,sizeof(x));memset(y,-1,sizeof(y));for(i=1;i<=m;i++){for(lx[i]=-inf,j=1;j<=n;j++)if(lx[i]<g[i][j])lx[i]=g[i][j];}for(i=1;i<=m;i++){for(j=1;j<=n;j++)slack[j]=inf;while(x[i]==-1){memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));if(search(i)) break;//更新顶标for(min=inf,j=1;j<=n;j++)if(!vy[j]&&slack[j]<min)min=slack[j];            for(j=1;j<=m;j++)                if(vx[j]) lx[j]-=min;            for(j=1;j<=n;j++)                if(vy[j]) ly[j]+=min;                else slack[j]-=min;}}for(ans=0,i=1;i<=n;i++){    if(y[i]==-1) return -1;//无匹配    if(g[y[i]][i]==-inf) return -1;    ans+=g[y[i]][i];}return ans;}void dfs(int i){int j;if(i==n+1){printf("Best Pairing %d\n",num++);for(j=1;j<=n;j++)printf("Supervisor %d with Employee %d\n",j,x[j]);return ;}for(j=1;j<=n;j++)if(map[i][j]&&!vy[j]){vy[j]=1;x[i]=j;dfs(i+1);vy[j]=0;}}int main(){int t,i,j,k,cas=1;scanf("%d",&t);while(t--){scanf("%d",&n);m=n;for(i=1;i<=n;i++)for(j=1;j<=n;j++){scanf("%d",&k);b[i][k]=j-1;}for(i=1;i<=n;i++)for(j=0;j<n;j++){scanf("%d",&k);a[i][k]=j;}for(i=1;i<=n;i++)for(j=1;j<=n;j++)g[i][j]=-(a[i][j]+b[j][i]);int ans=-1*KM();printf("Data Set %d, Best average difference: %lf\n",cas++,(ans*1.0)/(2*n*1.0));memset(map,0,sizeof(map));memset(vy,0,sizeof(vy));for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(lx[i]+ly[j]==g[i][j])map[i][j]=1;num=1;dfs(1);if(t!=0)printf("\n");}return 0;}

原创粉丝点击