HDU2255 奔小康赚小钱钱(二分图-最大带权匹配)

传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。 
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。 
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的). 

Input输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。 
Output请对每组数据输出最大的收入值,每组的输出占一行。 

Sample Input

2
100 10
15 23

Sample Output

123
题解:二分图的最大带权匹配模板题:理解匈牙利算法(或KM算法)模板即可过;
参考代码(KM算法优化后的,时间复杂度 O(n^3),可以作为模板):
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN = 305;
 4 const int INF = 0x3f3f3f3f;
 5 int love[MAXN][MAXN];   
 6 int ex_girl[MAXN],ex_boy[MAXN];       
 7 bool vis_girl[MAXN],vis_boy[MAXN];     
 8 int match[MAXN],slack[MAXN];       
 9 int N;
10 
11 bool dfs(int girl)
12 {
13     vis_girl[girl]=true;
14     for(int boy=0;boy<N;++boy) 
15     {
16         if(vis_boy[boy]) continue;
17         int gap=ex_girl[girl]+ex_boy[boy]-love[girl][boy];
18         if(gap == 0) 
19         { 
20             vis_boy[boy] = true;
21             if (match[boy] == -1 || dfs( match[boy] )) 
22             {    
23                 match[boy] = girl;
24                 return true;
25             }
26         }
27         else slack[boy] = min(slack[boy], gap);  
28     }
29     return false;
30 }
31 
32 int KM()
33 {
34     memset(match,-1,sizeof match);    
35     memset(ex_boy,0,sizeof ex_boy);  
36     for(int i=0;i<N;++i) 
37     {
38         ex_girl[i]=love[i][0];
39         for(int j=1;j<N;++j)  ex_girl[i]=max(ex_girl[i],love[i][j]);
40     }
41     for(int i=0;i<N;++i) 
42     {
43         fill(slack,slack+N,INF);    
44         while(1)
45         {
46             memset(vis_girl,false,sizeof vis_girl);
47             memset(vis_boy,false,sizeof vis_boy);
48             if(dfs(i)) break;  
49             int d=INF;
50             for(int j=0;j<N;++j) if(!vis_boy[j]) d=min(d,slack[j]);
51             for(int j=0;j<N;++j) 
52             { 
53                 if(vis_girl[j]) ex_girl[j]-=d;
54                 if(vis_boy[j]) ex_boy[j]+=d;  
55                 else slack[j]-=d;
56             }
57         }
58     }
59     int res=0;
60     for(int i=0;i<N;++i) res+=love[match[i]][i];
61     return res;
62 }
63 
64 int main()
65 {
66     while(~scanf("%d", &N)) 
67     {
68         for(int i = 0; i < N; ++i)
69             for(int j = 0; j < N; ++j)
70                 scanf("%d", &love[i][j]);
71         printf("%d
", KM());
72     }
73     return 0;
74 }
View Code
原文地址:https://www.cnblogs.com/csushl/p/9520575.html