HDU 2255 奔小康赚大钱 (KM算法 模板题)

 

 

 

奔小康赚大钱

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2129    Accepted Submission(s): 923

Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。

这可是一件大事,关系到人民的住房问题啊。村里共有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  

 

Source
HDOJ 2008 Summer Exercise(4)- Buffet Dinner  

 

Recommend lcy         从这个神牛那学来的模板:
http://www.cnblogs.com/jackge/archive/2013/05/03/3057028.html   里面有解释。   网上也好多KM算法的讲解。     不管了,会用就行了,套模板

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <iostream>
 5 using namespace std;
 6 
 7 /*  KM算法
 8  *   复杂度O(nx*nx*ny)
 9  *  求最大权匹配
10  *   若求最小权匹配,可将权值取相反数,结果取相反数
11  *  点的编号从0开始
12  */
13 const int N = 310;
14 const int INF = 0x3f3f3f3f;
15 int nx,ny;//两边的点数
16 int g[N][N];//二分图描述
17 int linker[N],lx[N],ly[N];//y中各点匹配状态,x,y中的点标号
18 int slack[N];
19 bool visx[N],visy[N];
20 
21 bool DFS(int x)
22 {
23     visx[x] = true;
24     for(int y = 0; y < ny; y++)
25     {
26         if(visy[y])continue;
27         int tmp = lx[x] + ly[y] - g[x][y];
28         if(tmp == 0)
29         {
30             visy[y] = true;
31             if(linker[y] == -1 || DFS(linker[y]))
32             {
33                 linker[y] = x;
34                 return true;
35             }
36         }
37         else if(slack[y] > tmp)
38             slack[y] = tmp;
39     }
40     return false;
41 }
42 int KM()
43 {
44     memset(linker,-1,sizeof(linker));
45     memset(ly,0,sizeof(ly));
46     for(int i = 0;i < nx;i++)
47     {
48         lx[i] = -INF;
49         for(int j = 0;j < ny;j++)
50             if(g[i][j] > lx[i])
51                 lx[i] = g[i][j];
52     }
53     for(int x = 0;x < nx;x++)
54     {
55         for(int i = 0;i < ny;i++)
56             slack[i] = INF;
57         while(true)
58         {
59             memset(visx,false,sizeof(visx));
60             memset(visy,false,sizeof(visy));
61             if(DFS(x))break;
62             int d = INF;
63             for(int i = 0;i < ny;i++)
64                 if(!visy[i] && d > slack[i])
65                     d = slack[i];
66             for(int i = 0;i < nx;i++)
67                 if(visx[i])
68                     lx[i] -= d;
69             for(int i = 0;i < ny;i++)
70             {
71                 if(visy[i])ly[i] += d;
72                 else slack[i] -= d;
73             }
74         }
75     }
76     int res = 0;
77     for(int i = 0;i < ny;i++)
78         if(linker[i] != -1)
79             res += g[linker[i]][i];
80     return res;
81 }
82 //HDU 2255
83 int main()
84 {
85     int n;
86     while(scanf("%d",&n) == 1)
87     {
88         for(int i = 0;i < n;i++)
89             for(int j = 0;j < n;j++)
90                 scanf("%d",&g[i][j]);
91         nx = ny = n;
92         printf("%d\n",KM());
93     }
94     return 0;
95 }

 

       

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/p/3228861.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞