HDU - 奔小康赚大钱(二分图最佳匹配+KM)
发布日期:2021-07-01 00:16:26 浏览次数:2 分类:技术文章

本文共 2615 字,大约阅读时间需要 8 分钟。

题目链接:

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

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

Problem solving report:

Description: 二分图最大权匹配。

Problem solving: KM模板题。建立二分图,一边为N家老百姓,另一边为N间房子。对老百姓和房子之间估价建立一条有带权边。问题就转变为了再二分图中找出一个总权值最大的匹配,也就是加权二分图最佳匹配问题。
参考博文1:
参考博文2:

#include 
#include
#include
using namespace std;const int MAXN = 330;const int inf = 0xffffff0;int link[MAXN], lx[MAXN], ly[MAXN], slack[MAXN];int n, visx[MAXN], visy[MAXN], map[MAXN][MAXN];int FindPath(int u){ visx[u] = 1; for (int i = 1; i <= n; i++) { if (visy[i]) continue; int temp = lx[u] + ly[i] - map[u][i]; if (!temp) { visy[i] = 1; if (link[i] == -1 || FindPath(link[i])) { link[i] = u; return 1; } } else if (slack[i] > temp) slack[i] = temp; } return 0;}int KM(){ memset(ly, 0, sizeof(ly)); memset(link, -1, sizeof(link)); for (int i = 1; i <= n; i++) { lx[i] = -inf; for (int j = 1; j <= n; j++) if (map[i][j] > lx[i]) lx[i] = map[i][j]; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) slack[j] = inf; while (1) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if (FindPath(i)) break; int d = inf; for (int j = 1; j <= n; j++) if (!visy[j] && d > slack[j]) d = slack[j]; for (int j = 1; j <= n; j++) { if (visx[j]) lx[j] -= d; if (visy[j]) ly[j] += d; else slack[j] -= d; } } } int res = 0; for (int i = 1; i <= n; ++i) if (link[i] > -1) res += map[link[i]][i]; return res;}int main(){ while (~scanf("%d", &n)) { for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) scanf("%d", &map[i][j]); printf("%d\n", KM()); } return 0;}

转载地址:https://lzyws739307453.blog.csdn.net/article/details/86995909 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:ZOJ - Rearrange Them(DP)
下一篇:HDU - FATE(二维完全背包)

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月26日 02时24分27秒