hdu_2255_奔小康赚大钱(KM带权二分匹配板子)

题目连接: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 }
View Code



原文地址:https://www.cnblogs.com/bin-gege/p/5696081.html