http://acm.hdu.edu.cn/showproblem.php?pid=2255
/*
最优匹配:使二分图的边权和最大的完备匹配。(如果二分图的两个点集不相等可以通过加 ’点‘ 和 ’权值为0的边‘ 实现转化)
#include<stdio.h> #include<string.h> #define N 305 #define Max 1000000 int w[N][N],linky[N]; //数组 w 记录边权,数组 linky 记录顶点 y 的匹配; int lx[N],ly[N]; //数组 lx 和 ly 分别记录顶点 x 和 y 的顶标值; int visx[N],visy[N]; //数组 visx 和 visy 分别记录顶点 x 和 y 是否被访问; int n,low; //low 记录每次顶标需要变化的值; int Find(int x) { int y,t; visx[x]=1; for(y=0;y<n;y++){ if(visy[y])continue; t=lx[x]+ly[y]-w[x][y]; if(t==0){ visy[y]=1; if(linky[y]==-1||Find(linky[y])){ linky[y]=x; return 1; } } else{ if(low>t)low=t; } } return 0; } void KM() { int i,x; for(x=0;x<n;x++){ while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); low=Max; if(Find(x))break; for(i=0;i<n;i++){ if(visx[i]) lx[i]-=low; if(visy[i]) ly[i]+=low; } } } } int main() { int i,j,sum; while(scanf("%d",&n)!=EOF){ memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(linky,-1,sizeof(linky)); for(i=0;i<n;i++){ for(j=0;j<n;j++){ scanf("%d",&w[i][j]); if(lx[i]<w[i][j]) lx[i]=w[i][j]; } } KM(); for(i=0,sum=0;i<n;i++){ sum+=w[linky[i]][i]; } printf("%d\n",sum); } return 0; }