POJ 2400 Supervisor, Supervisee
二分图最优匹配第二题,KM算法。
题目大意:
一共有N个管理者和N个雇员,每个雇员会跟随一个管理者。每个雇员会对管理者的喜好程度进行排名,管理者也同样会对雇员进行排名,问如何对管理者和雇员进行配对使总排名的平均值最小。
解题思路:
KM算法求最小权的匹配。
下面是代码:
#include <stdio.h> #include <string.h> const int inf=1<<30; int w[20][20],n,km1[20],km2[20],d,pre[20],cnt,ans; bool visx[20],visy[20]; void init() { memset(km2,0,sizeof(km2)); memset(pre,-1,sizeof(pre)); for(int i=1; i<=n; i++) { km1[i]=w[i][1]; for(int j=2; j<=n; j++) { if(km1[i]<w[i][j])km1[i]=w[i][j]; } } } bool dfs(int src) { visx[src]=true; for(int i=1; i<=n; i++) { if(!visy[i]) { int t=km1[src]+km2[i]-w[src][i]; if(!t) { visy[i]=true; if(pre[i]==-1||dfs(pre[i])) { pre[i]=src; return true; } } else if(d>t)d=t; } } return false; } int km() { for(int i=1; i<=n; i++) { while(1) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); d=inf; if(dfs(i))break; for(int j=1; j<=n; j++) { if(visx[j])km1[j]-=d; if(visy[j])km2[j]+=d; } } } ans=0; for(int i=1; i<=n; i++) { if(pre[i]!=-1)ans+=w[pre[i]][i]; } return -ans; } void dfs(int src,int ca) { if(ca<ans)return; if(src>n) { if(ca!=ans)return; printf("Best Pairing %d\n",cnt++); for(int i=1; i<=n; i++) { printf("Supervisor %d with Employee %d\n",i,pre[i]); } } else { for(int i=1; i<=n; i++) { if(!visx[i]) { visx[i]=true; pre[src]=i; dfs(src+1,ca+w[src][i]); visx[i]=false; } } } } int main() { int t,x,case1=1; scanf("%d\n",&t); while(t--) { scanf("%d\n",&n); memset(w,0,sizeof(w)); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { scanf("%d",&x); w[x][i]-=(j-1); } } for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { scanf("%d",&x); w[i][x]-=(j-1); } } init(); printf("Data Set %d, Best average difference: %lf\n",case1++,(km()*0.5)/n); memset(visx,0,sizeof(visx)); cnt=1; dfs(1,0); printf("\n"); } return 0; }