题目连接:hdu_2255_奔小康赚大钱
存个板子
1 /* 2 其实在求最大 最小的时候只要用一个模板就行了, 3 把边的权值去相反数即可得到另外一个.求结果的时候再去 4 相反数即可,最大最小有一些地方不同。。 5 */ 6 #include <iostream> 7 #include<cstring> 8 #include<cstdio> 9 #include<cmath> 10 const int N = 301; 11 const int INF = (1<<30)-1; 12 int w[N][N]; 13 int lx[N],ly[N]; //顶标 14 int linky[N],visx[N],visy[N],slack[N]; 15 int n; 16 bool find(int x){ 17 visx[x]=1; 18 for(int y=1;y<=n;y++){ 19 if(visy[y])continue; 20 int t=lx[x]+ly[y]-w[x][y]; 21 if(t==0){ 22 visy[y] = 1; 23 if(linky[y]==-1||find(linky[y]))return linky[y]=x,1; 24 } 25 else if(slack[y]>t)slack[y]=t; 26 } 27 return 0; 28 } 29 30 int KM(){ 31 int i,j; 32 memset(linky,-1,sizeof(linky)); 33 memset(ly,0,sizeof(ly)); 34 for(i=1;i<=n;i++){ 35 lx[i]=-INF; 36 for(j = 1;j<=n;j++) 37 if(w[i][j]>lx[i])lx[i]=w[i][j]; 38 } 39 for(int x=1;x<=n;x++){ 40 for(i=1;i<=n;i++)slack[i]=INF; 41 while(1){ 42 memset(visx,0,sizeof(visx)); 43 memset(visy,0,sizeof(visy)); 44 if(find(x))break;//找到增广轨,退出 45 int d=INF; 46 for(i=1;i<=n;i++) //没找到,对l做调整(这会增加相等子图的边),重新找 47 if(!visy[i]&&d>slack[i])d=slack[i]; 48 for(i=1;i<=n;i++)if(visx[i])lx[i]-=d; 49 for(i=1;i<=n;i++) 50 if(visy[i])ly[i]+=d;else slack[i]-=d; 51 } 52 } 53 int result = 0; 54 for(i=1;i<=n;i++)if(linky[i]>-1)result+=w[linky[i]][i]; 55 return result; 56 } 57 58 int main() 59 { 60 while(scanf("%d",&n)==1) 61 { 62 int cost; 63 for(int i=1;i<=n;i++) 64 for(int j=1;j<=n;j++) 65 { 66 scanf("%d",&cost); 67 w[i][j]=cost; 68 } 69 printf("%d ",KM()); 70 } 71 return 0; 72 }