zoukankan      html  css  js  c++  java
  • 图论:匹配与覆盖+独立集 团与支配集

    计算机算法里面有:二分图匹配算法。将节点划分到两个集合,两边之间的点连线生成边。
        匹配:指的是无向图的边集的一个子集,使得这个子集中的任意两条边没有公共顶点且不包含自环。
            如果一个匹配不是其他匹配的子集,那么称这个匹配为极大匹配。在极大匹配中添加任意一条其他的
        边生成的集合都不是匹配。
        
        顶点覆盖:是指无向图的点集的一个子集,使得边集中的任意一条边都至少有一个端点在这个子集中。
        顶点覆盖的大小即为 顶点覆盖中的点的个数。
            如果其他的顶点覆盖都不是这个顶点覆盖的子集,则称这个顶点覆盖为:极小顶点覆盖。
        同理,可以推出边覆盖的定义。
        
        1.任意一个顶点覆盖的补集,一定是一个独立集。反之亦然。
        2.最小顶点覆盖+最大独立集 = V
        3.最大匹配中的所有端点组成的点集是一个顶点覆盖。
        4.在二分图中,最小顶点覆盖和最大匹配在数值上相等

    独立集:是指无向图中点集的一个子集,其中任意两个点不相邻(即:没有变将他们连到一起)。不会存在某一条边

    可以连接独立集中的两个点。等价于: 任意一条边最多有一个端点在独立集里。

    最大的独立集称为:最大独立集。

    团:与独立集的定义相对,团是指无向图中点集的一个子集,其中任意两点都有边连接。最大的团成为最大团。

    支配集:是指无向图中点集的一个子集,所有无向图中的点,要么属于这个子集,要么与这个子集中的点相邻。

    最小的支配集称为最小支配集。

         1.一个极大独立集一定是一个支配集。

         2.最小支配集不一定是独立集,但最小支配集的大小必然小于等于最小的极大独立集的大小。

         3.图G的最大团 = 图G的补图的最大独立集。

         4.最小顶点覆盖+最大独立集 = V

    例题:hihocoder #1127 : 二分图三·二分图最小点覆盖和最大独立集

    输入

    第1行:2个正整数,N,M(N表示点数 2≤N≤1,000,M表示边数1≤M≤5,000)
    第2..M+1行:每行两个整数u,v,表示一条无向边(u,v)

    输出

    第1行:1个整数,表示最小点覆盖数
    第2行:1个整数,表示最大独立集数

    样例输入
    5 4
    3 2
    1 3
    5 4
    1 5
    样例输出
    2
    3

    代码:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <math.h>
    #include <deque>
    #include <algorithm>
    #define eps 1e-8
    #define N 1010
    
    using namespace std;
    
    int n, m;
    int g[N][N];
    int link[N];
    bool vis[N];
    
    int dfs(int dd)
    {
    	for(int i=1; i<=n; i++){
    		if(!vis[i] && g[dd][i]==1 )
    		{
    			vis[i]=true;
    			if(link[i]==-1 || dfs(link[i]) ){
    				link[i]=dd;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    
    int main()
    {
    	scanf("%d %d", &n, &m);
    
    	int i, j; int u,v;
    	memset(g, 0, sizeof(g));
    	memset(link, -1, sizeof(link));
    
    	for(i=0; i<m; i++)
    	{
    		scanf("%d %d", &u, &v);
    		g[u][v]=1; g[v][u]=1; //建立双向边
    	}
    	int cnt=0;
    	for(i=1; i<=n; i++){
    		memset(vis, false, sizeof(vis));
    		cnt+=dfs(i);
    	}
    	int ans1=cnt/2; //最小点覆盖=最大匹配数
    	int ans2=n-ans1; //最大独立集=V-最小点覆盖
    	printf("%d
    %d
    ", ans1, ans2 );
    
        return 0;
    }
    
  • 相关阅读:
    MySQL创建数据库简单命令
    工作的本质是解决问题
    使用消息中间件时,如何保证消息仅仅被消费一次?
    缓存穿透了怎么办?
    MySQL 数据库的提速器-写缓存(Change Buffer)
    删库了,我们一定要跑路吗?
    做好一件事的三要素
    一分钟简单了解 JSON Web Token
    聊一聊 MySQL 中的数据编辑过程中涉及的两阶段提交
    聊一聊 MySQL 数据库中的那些锁
  • 原文地址:https://www.cnblogs.com/yspworld/p/4672440.html
Copyright © 2011-2022 走看看