zoukankan      html  css  js  c++  java
  • hdu 2255 奔小康赚大钱 最佳匹配 KM算法

    完备匹配,X集合中每个都有匹配,或Y集合中每个都有匹配。

    最佳匹配,权值和最大的完备匹配称为最佳匹配。

    添加一些边权为0的边,就能将最大权匹配和最佳匹配统一起来。

    KM算法流程,我们假定X集合大小不超过Y集合。

    开始X集合每个点给一个标签,值为其最大相邻边边权,Y集合每个点标签为0。

    如果一条边的两个端点的标签和为边权,则认为这条边是可用的。我们每次在可用边上做匈牙利算法,如果找到匹配边则退出,找下一个点的匹配边。否则将匹配过程经过的所有X集合的点的标签减少一个d,经过的所有Y集合的点的标签增加一个d。然后重新在可用边上做匈牙利算法。显然这个d应该是刚刚匹配过程中,标签和和边权的最小差值。

    KM算法核心,就是我们通过给经过的X集合点增加d,给经过Y集合点减少d。使得两个端点都经过的边,依旧可用。两个端点都没经过的边,依旧保持其原状态。经过X集合端点,没经过Y集合端点的不可用边,现在标签和变小,可能可用。没记过X集合端点,经过Y集合端点的不可用边,现在标签和变大,依旧不可用。所以创造了一个新的边权和最大的可能成功的匹配。

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 const int inf = 1000000000;
     5 int n,ans,mind;
     6 int mp[310][310],lbx[310],lby[310],mth[310];
     7 bool visx[310],visy[310];
     8 bool find(int x)
     9 {
    10     visx[x] = true;
    11     for (int i = 1;i <= n;i++)
    12     {
    13         if (visy[i])
    14             continue;
    15         int t = lbx[x] + lby[i] - mp[x][i];
    16         if (t == 0)
    17         {
    18             visy[i] = true;
    19             if (mth[i] == 0 || find(mth[i]))
    20             {
    21                 mth[i] = x;
    22                 return true;
    23             }
    24         }else25             mind = min(mind,t);
    26     }
    27     return false;
    28 }
    29 void KM()
    30 {
    31     for (int i = 1;i <= n;i++)
    32     {
    33         lbx[i] = 0;
    34         for (int j = 1;j <= n;j++)
    35             lbx[i] = max(lbx[i],mp[i][j]);
    36     }
    37     for (int i = 1;i <= n;i++)
    38     {
    39         lby[i] = 0;
    40         mth[i] = 0;
    41     }
    42     for (int i = 1;i <= n;i++)
    43     {
    44         for (;;)
    45         {
    46             for (int j = 1;j <= n;j++)
    47                 visx[j] = 0;
    48             for (int j = 1;j <= n;j++)
    49                 visy[j] = 0;
    50             mind = inf;
    51             if (find(i))
    52                 break;
    53             for (int j = 1;j <= n;j++)
    54                 if (visx[j]) 
    55                     lbx[j] -= mind;
    56             for (int j = 1;j <= n;j++)
    57                 if (visy[j]) 
    58                     lby[j] += mind;
    59         }
    60     }
    61 }
    62 int main()
    63 {
    64     for (;scanf("%d",&n) > 0;)
    65     {
    66         for (int i = 1;i <= n;i++)
    67             for (int j = 1;j <= n;j++)
    68                 scanf("%d",&mp[i][j]);
    69         KM();
    70         ans = 0;
    71         for (int i = 1;i <= n;i++)
    72             if (mth[i] != 0)
    73                 ans += mp[mth[i]][i];
    74         printf("%d
    ",ans);
    75     }
    76     return 0;
    77 }
    心之所动 且就随缘去吧
  • 相关阅读:
    20130912对象生命周期基础
    ASP.Net 提交表单 post 方式代码
    Design Service Develop Created new Field(1)
    asp.net 调用存储过程(带有输入,输出参数 ,思路)二
    工作流概述
    asp.net 调用存储过程(带有输入,输出参数 范例)二
    如何配置服务器上面的Excel组件访问权限
    C# 模拟网站登陆
    NPOI创建DOCX常用操作
    SQL CPU高排查
  • 原文地址:https://www.cnblogs.com/iat14/p/11817996.html
Copyright © 2011-2022 走看看