zoukankan      html  css  js  c++  java
  • 最大流增广路(KM算法) HDOJ 2255 奔小康赚大钱

    题目传送门

     1 /*
     2     KM:裸题第一道,好像就是hungary的升级版,不好理解,写点注释
     3         KM算法用来解决最大权匹配问题: 在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接Xi,Yj有权w(i,j),
     4         求一种匹配使得所有w(i,j)的和最大。也就是最大权匹配一定是完备匹配。如果两边的点数相等则是完美匹配。
     5         如果点数不相等,其实可以虚拟一些点,使得点数相等,也成为了完美匹配。最大权匹配还可以用最大流去解决
     6 */
     7 #include <cstdio>
     8 #include <algorithm>
     9 #include <cstring>
    10 using namespace std;
    11 
    12 const int MAXN = 3e2 + 10;
    13 const int INF = 0x3f3f3f3f;
    14 int x[MAXN], y[MAXN], w[MAXN][MAXN];
    15 int lx[MAXN], ly[MAXN];
    16 bool visx[MAXN], visy[MAXN];
    17 int n, d;
    18 
    19 bool DFS(int u)    {        //hungary算法
    20     visx[u] = true;
    21     for (int i=1; i<=n; ++i)    {
    22         if (x[u] + y[i] == w[u][i] && !visy[i])    {
    23             visy[i] = true;
    24             if (ly[i] == -1 || DFS (ly[i]))    {
    25                 ly[i] = u;    return true;
    26             }
    27         }
    28         else if (x[u] + y[i] > w[u][i])    d = min (d, x[u] + y[i] - w[u][i]);        //更新d,贪心思想
    29     }
    30 
    31     return false;
    32 }
    33 
    34 void KM(void)    {
    35     for (int i=1; i<=n; ++i)    {
    36         x[i] = 0;
    37         for (int j=1; j<=n; ++j)    {
    38             x[i] = max (x[i], w[i][j]);        //初始x标杆为最大值w,y为0
    39         }
    40     }
    41 
    42     memset (y, 0, sizeof (y));
    43     memset (ly, -1, sizeof (ly));
    44     for (int i=1; i<=n; ++i)    {
    45         while (true)    {
    46             memset (visx, false, sizeof (visx));
    47             memset (visy, false, sizeof (visy));
    48             d = INF;
    49             if (DFS (i))    break;            //找到增广轨,退出
    50             for (int i=1; i<=n; ++i)    {        //没有找到,对标杆进行调整
    51                 if (visx[i])    x[i] -= d;
    52                 if (visy[i])    y[i] += d;
    53             }
    54         }
    55     }
    56 
    57     int res = 0;
    58     for (int i=1; i<=n; ++i)    {
    59         res += x[i] + y[i];
    60     }
    61     printf ("%d
    ", res);
    62 }
    63 
    64 int main(void)    {        //HDOJ 2255 奔小康赚大钱
    65     //freopen ("HDOJ_2255.in", "r", stdin);
    66 
    67     while (scanf ("%d", &n) == 1)    {
    68         for (int i=1; i<=n; ++i)    {
    69             for (int j=1; j<=n; ++j)    {
    70                 scanf ("%d", &w[i][j]);
    71             }
    72         }
    73         KM ();
    74     }
    75 
    76     return 0;
    77 }
    编译人生,运行世界!
  • 相关阅读:
    08月24日总结
    08月23日总结
    08月22日总结
    装饰器
    卢菲菲最强大脑记忆训练法全套教程 01
    LeetCode 704 二分查找
    LeetCode 1480 一维数组的动态和
    NIO 总结
    LeetCode 881 救生艇
    url的组成部分
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4661950.html
Copyright © 2011-2022 走看看