hdu-2255 奔小康赚大钱---KM模板
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2255
题目大意:
Problem Description
传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).
这可是一件大事,关系到人民的住房问题啊。村里共有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算法模板:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<map> 6 using namespace std; 7 typedef long long ll; 8 const int maxn = 300 + 10; 9 const int INF = 0x3f3f3f3f; 10 11 int wx[maxn], wy[maxn];//每个点的顶标值(需要根据二分图处理出来) 12 int cx[maxn], cy[maxn];//每个点所匹配的点 13 int visx[maxn], visy[maxn];//每个点是否加入增广路 14 int cntx, cnty;//分别是X和Y的点数 15 int Map[maxn][maxn];//二分图边的权值 16 int minz;//边权和顶标最小的差值 17 18 bool dfs(int u)//进入DFS的都是X部的点 19 { 20 visx[u] = 1;//标记进入增广路 21 for(int v = 1; v <= cnty; v++) 22 { 23 if(!visy[v] && Map[u][v] != INF)//如果Y部的点还没进入增广路,并且存在路径 24 { 25 int t = wx[u] + wy[v] - Map[u][v]; 26 if(t == 0)//t为0说明是相等子图 27 { 28 visy[v] = 1;//加入增广路 29 30 //如果Y部的点还未进行匹配 31 //或者已经进行了匹配,可以从原来的匹配反向找到增广路 32 //那就可以进行匹配 33 if(cy[v] == -1 || dfs(cy[v])) 34 { 35 cx[u] = v; 36 cy[v] = u;//进行匹配 37 return 1; 38 } 39 } 40 else if(t > 0)//此处t一定是大于0,因为顶标之和一定>=边权 41 { 42 minz = min(minz, t);//边权和顶标最小的差值 43 } 44 } 45 } 46 return false; 47 } 48 49 int KM() 50 { 51 memset(cx, -1, sizeof(cx)); 52 memset(cy, -1, sizeof(cy)); 53 memset(wx, 0, sizeof(wx));//wx的顶标为该点连接的边的最大权值 54 memset(wy, 0, sizeof(wy));//wy的顶标为0 55 for(int i = 1; i <= cntx; i++)//预处理出顶标值 56 { 57 for(int j = 1; j <= cnty; j++) 58 { 59 if(Map[i][j] == INF)continue; 60 wx[i] = max(wx[i], Map[i][j]); 61 } 62 } 63 for(int i = 1; i <= cntx; i++)//枚举X部的点 64 { 65 while(1) 66 { 67 minz = INF; 68 memset(visx, 0, sizeof(visx)); 69 memset(visy, 0, sizeof(visy)); 70 if(dfs(i))break;//已经匹配正确 71 72 //还未匹配,将X部的顶标减去minz,Y部的顶标加上minz 73 for(int j = 1; j <= cntx; j++) 74 if(visx[j])wx[j] -= minz; 75 for(int j = 1; j <= cnty; j++) 76 if(visy[j])wy[j] += minz; 77 } 78 } 79 80 int ans = 0;//二分图最优匹配权值 81 for(int i = 1; i <= cntx; i++) 82 if(cx[i] != -1)ans += Map[i][cx[i]]; 83 return ans; 84 } 85 int n, k; 86 int main() 87 { 88 while(scanf("%d", &n) != EOF) 89 { 90 for(int i = 1; i <= n; i++) 91 { 92 for(int j = 1; j <= n; j++) 93 scanf("%d", &Map[i][j]); 94 } 95 cntx = cnty = n; 96 printf("%d\n", KM()); 97 } 98 return 0; 99 }
越努力,越幸运