zoukankan      html  css  js  c++  java
  • 二分图 匈牙利 算法 (模版)

    以前就做过 二分图,在另一个 博客 里 ,现在 搬过来 了。。

    这里求的是最大匹配

    匈牙利算法的基本知识:

    百度百科:


    http://baike.baidu.com/view/501092.htm

    维基百科: 这里面有邻接矩阵的模拟图


    http://en.wikipedia.org/wiki/Hungarian_algorithm

    二分图定理总结


    原文地址

    ========

    对于任意图:

    |最小边覆盖|+|最大匹配|=|V|

    二分图的最大匹配=最小点覆盖数

    对于二分图:

    以下数值等价.

    最大匹配

    最小点覆盖

    |V|-最大独立集(二分图or有向无环图)

    |V|-最小边覆盖数

    |V|-最小路径覆盖数(有向无环图)

    |V|-最小路径覆盖数/2(无向图)

    (上面括号里有有向无环图的,均是将一个点拆成两个点连边匹配)

    由于任意图的那几个几乎用不到于是这里只贴二分图的定义

    最小点覆盖:理解为点覆盖边,即用最小的点覆盖所有的边。(若一条边的其中一个端点被选用,这条边就被覆盖了)

    最大独立集:求一个最大的点集,里面的点不存在任何的边相连。

    最小边覆盖:理解为边覆盖点,用最少的边把图中的点全部覆盖。

    最小路径覆盖:用最少的路径把图中的所有点覆盖。

    另外:最大独立集与最小覆盖集互补。

    推广到有权的形式也一样,即最大点权独立集最小点权覆盖集互补

    求最小点权覆盖集可以这样求:

    先对图黑白染色,然后向白色的点放X部,黑色的点放Y部。

    1、连边[S,i],容量等于i的点权。(对于二分图的X集)

    2、连边[i,T],容量等于i的点权。(对于二分图的Y集)

    3、对于有边的i和j连边[i,j](i∈X,j∈Y),容量为INF

    最后得出的最大流就是最小点权覆盖,实际上是最小割与之对应。

    对于求了传递闭包以后的有向无环图:

    最大反链=|V|-最大匹配

     1 #include <stdio.h>
     2 
     3 #include <string.h>
     4 
     5 int n1, n2, m, ans;
     6 
     7 int result[101]; //记录V2中的点匹配的点的编号
     8 bool state [101]; //记录V2中的每个点是否被搜索过
     9 bool data[101][101];//邻接矩阵 true代表有边相连
    10 void init()
    11 
    12 {
    13 
    14     int t1, t2;
    15 
    16     memset(data, 0sizeof(data));
    17 
    18     memset(result, 0sizeof(result));
    19 
    20     ans = 0;
    21 
    22     scanf("%d%d%d", &n1, &n2, &m);
    23 
    24     for (int i = 1; i <= m; i++)
    25 
    26     {
    27 
    28      scanf("%d%d", &t1, &t2);k
    29 
    30      data[t1][t2] = true;
    31 
    32     }
    33 
    34     return;
    35 
    36 }
    37 
    38 bool find(int a)
    39 
    40 {
    41 
    42     for (int i = 1; i <= n2; i++)
    43 
    44     {
    45 
    46        if (data[a][i] == 1 && !state[i]) //如果节点i与a相邻并且未被查找过
    47         {
    48 
    49           state[i] = true//标记i为已查找过
    50           if (result[i] == 0 //如果i未在前一个匹配M中
    51           || find(result[i])) //i在匹配M中,但是从与i相邻的节点出发可以有增广路
    52           {
    53 
    54             result[i] = a; //记录查找成功记录
    55             return true//返回查找成功
    56           }
    57 
    58          }
    59 
    60     }
    61 
    62     return false;
    63 
    64 }
    65 
    66 int main()
    67 
    68 {
    69 
    70     init();
    71 
    72     for (int i = 1; i <= n1; i++)
    73 
    74     {
    75 
    76        memset(state, 0sizeof(state)); //清空上次搜索时的标记
    77        if (find(i)) ans++; //从节点i尝试扩展(每一次增加一条边 或一个顶点)
    78     }
    79 
    80     printf("%d\n", ans);
    81 
    82 return 0;
    83 
    84 }

    邻接表:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cmath>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<set>
     7 #include<map>
     8 #include<queue>
     9 #include<vector>
    10 #include<string>
    11 #define Min(a,b) a<b?a:b
    12 #define Max(a,b) a>b?a:b
    13 #define CL(a,num) memset(a,num,sizeof(a));
    14 #define eps  1e-6
    15 #define inf 10001000
    16 
    17 #define ll   __int64
    18 
    19 #define  read()  freopen("data.txt","r",stdin) ;
    20 const double pi  = acos(-1.0);
    21 const int maxn = 200;
    22 
    23 using namespace std;
    24 int n,m;
    25 int head[maxn] ;
    26 int result[maxn],vis[maxn] ;
    27 struct node
    28 {
    29     int v;
    30     int next;
    31 }p[maxn*maxn];
    32 int cnt ;
    33 void add(int u,int v)
    34 {
    35     p[cnt].v = v;
    36     p[cnt].next = head[u];
    37     head[u] = cnt++ ;
    38 }
    39 bool find(int u)
    40 {
    41 
    42     for(int i = head[u];i!= -1;i = p[i].next)
    43     {
    44         int v = p[i].v ;
    45         if(!vis[v])
    46         {
    47             vis[v] = 1 ;
    48             if(result[v] == -1||find(result[v]))
    49             {
    50                 result[v] = u;
    51                 return true;
    52             }
    53         }
    54     }
    55     return false ;
    56 }
    57 int get()
    58 {
    59     int ans= 0;
    60     CL(result,-1);
    61     for(int i = 1;i <= n;i++)
    62     {
    63         CL(vis,0);
    64         if(find(i))ans++;
    65     }
    66     return ans ;
    67 }
    68 int main()
    69 {
    70     //read() ;
    71     int t ,i,x,y;
    72     scanf("%d",&t);
    73     while(t--)
    74     {
    75         cnt = 0;
    76         CL(head,-1) ;
    77         scanf("%d%d",&n,&m);
    78         for(i = 0 ; i < m;i++)
    79         {
    80             scanf("%d%d",&x,&y);
    81             add(x,y);
    82         }
    83         int ans = get() ;
    84         printf("%d\n",n - ans) ;
    85     }
    86 }
  • 相关阅读:
    保证测试通过的ip正则,antdIP/IP段的校验方法,antd的textArea中可以输入多个以换行分隔的ip/IP段,并自动检测出错行的原因
    TP5接口出错只能返回500
    UDP服务只能本机访问问题
    有出现了找半天的小BUG
    PHP本地安装redis扩展
    MYSQL数据库和es数据库同步
    QQ互联应用申请失败
    axios跨域问题解决
    elastic和kibana安装心得
    自增运算符理解
  • 原文地址:https://www.cnblogs.com/acSzz/p/2683915.html
Copyright © 2011-2022 走看看