zoukankan      html  css  js  c++  java
  • 图的联通性

    图的联通性

    0.【前置知识】 图上dfs相关概念

    vis数组:在图的遍历中,往往设置了一个标记数组vis的bool值来记录顶点是否被访问过。但有些时候需要改变vis值的意义。令vis具有3种值并表示3种不同含义

    vis = 0,表示该顶点没没有被访问

    vis = 1,表示该顶点已经被访问,但其子孙后代还没被访问完,也就没从该点返回

    vis = 2,表示该顶点已经被访问,其子孙后代也已经访问完,也已经从该顶点返回

    可以vis的3种值表示的是一种顺序关系和时间关系。

    DFS过程中,对于一条边u->v

    vis[v] = 0,说明v还没被访问,v是首次被发现,u->v是一条树边又称树枝边

    vis[v] = 1,说明v已经被访问,但其子孙后代还没有被访问完(正在访问中),而u又指向v?说明u就是v的子孙后代,u->v是一条后向边,因此后向边又称返祖边

    vis[v] = 2,说明v已经被访问,其子孙后代也已经全部访问完,u->v这条边可能是一条横叉边,或者前向边

    1.无向图的联通性

    联通:两点存在一条连接它们的路径。

    联通块:里面的点两两联通。

    桥:对于一个联通无向图,一条边是桥当且仅当去掉这条边后图变得不连通。

    强连通分量:没有桥的联通块。

    (无向图的强连通分量也叫边双联通分量,对应的概念是:

    点双连通:没有割点的双连通分量

    对于特定的题目会有求双连通分量的操作。)

    ​ tarjan算法判桥:

    ​ dfn[x]是dfs序,代表x是第几个搜到的。

    ​ instack[x]表示当前的点是否在dfs栈中,是用来判断是否是返祖边,代码中if(instack[y])即代表x点在y的子树中。

    ​ 不过无向图联通分量中instack数组是不必要的。

    由于无向图中都是双向边,前向边的情况对不更新low(tarjan中用if(instack[y])将前向边特判掉不更新)没有意义(证明:如果存在一条前向边u->v,则亦存在v->u,所以在dfs到v时已经更新了v。再dfs到v时,即使不更新也没意义了)所以

    ​ low[x] PPT:x通过非返祖边,且至多通过一条非树边能到达的最小dfn。

    ​ 我的理解:x至多通过一条非树边(即不是返回父亲的返祖边)能到达的最小dfn。

    ​ 感觉洪老师把返祖边的定义弄错(混)了:一方面字面上以为是返回父亲的边,另一方面代码里用的是instack正确的判断,导致没有判真正返回父亲的边。

    void tarjan(int x,int fa) {
    	instack[x] = 1;
    	dfn[x] = low[x] = ++tot;
    	for (auto y : E[x]) {
    		if (!dfn[y]) {
    			tarjan(y,x);
    			low[x] = min(low[x], low[y]);
    		}
    		else {
    			if(y!=fa&&instack[y])low[x] = min(low[x], dfn[y]);
    		}
    	}
    	instack[x] = 0;
    }
    //-----ppt中的错误代码,没有特判掉指向父亲的返祖边--------------
    void tarjan(int x) {
    	instack[x] = 1;
    	dfn[x] = low[x] = ++tot;
    	for (auto y : E[x]) {
    		if (!dfn[y]) {//树边
    			tarjan(y);
    			low[x] = min(low[x], low[y]);
    		}
    		else {
    			if(instack[y])low[x] = min(low[x], dfn[y]);//返祖边,一般指向父亲
    		}
    	}
    	instack[x] = 0;
    }
    

    判桥: low[x]<dfn[x]代表存在一条返回到父亲之上某点y的返祖边,y有一条路径到x,x有另一条路径到y。(形成双连通分量??)

    反之low[x]>=dfn[x]代表它连向父亲的边为桥

    2.有向图的联通性

    强连通分量:任意两点都可以互相到达。

    在做 Tarjan算法时,如果 tarjan(x) 后发现 dfn[x]==low[x],则 x 的⼦树⾥的剩下的所有点构成⼀个强连通分量,可以用一个栈来维护:

    stack<int> S;
    void tarjan(int x) {
    	S.push(x);
    	instack[x] = 1;
    	dfn[x] = low[x] = ++tot;
    	for (auto y : E[x]) {
    		if (!dfn[y]) {
    			tarjan(y, x);
    			low[x] = min(low[x], low[y]);
    		}
    		else {
    			if ( instack[y])low[x] = min(low[x], dfn[y]);
    		}
    	}
    	if (low[x] == dfn[x]) {
    		while (1) {
    			int now = S.top();
    			S.pop();
    			instack[x] = 0;//把之前没有清零的一次性更新。
    			/*
    				染色,统计之类的操作
    			*/
    			if (now == x)break;
    		}
    	}
    	
    }
    

    3.例题

    0.

    题意:

    有N个⼈,给你M对整数 (a,b),表示第 a 个⼈认为 b 很厉 害,⽽这种关系具备传递性,也就是如果 a 认为 b 厉害, 且 b 认为 c 厉害,则 a 认为 c 厉害

    求有多少⼈被所有⼈都觉得很厉害

    N,M<=10^5

    做法:

    无环:有向图无环 -> 至少有一个点没有出边。于是任意找一个点,一直走到没有出边的点,判一下是否所有点都连向它。

    有环:对于这样一个环,必为强连通,缩点后变成无环情况(会多出重边)。

    套路:一个题在没有环(是一个拓扑图)的时候很好做,就考虑缩环。

    1.POJ1236

    题意:

    给定一个有向图,N个点,求:

    1)至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点

    2)至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

    思路

    按照套路,Tarjan算法求SCC,并缩点建图。那么对于问题1,新的图中入度为0点的点数即是答案。

    对于问题2,答案为max(入度为0的点的点数,出度为0的点数),因为对于每个入度或出度为0的点,需要连一条边来解决,那么将出度为0的点连向入度为0的点是最优的。

    此外,如果最后SCC只有1个,那么问题2的答案应该特判为0。

    套路:有向图构造联通分量的方法:将出度为0的点连到入度为0的点上有向图。

    ​ 无向图构造联通分量的方法:将度为1的点(叶子)相互连接。

    2.POJ3177

    题意:有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走。现已有m条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路。两条独立的路是指:没有公共边的路,但可以经过同一个中间顶点。给出的图保证已经联通。

    思路:

    在同一个边双连通分量(即无向边的强连通分量)中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

    套路缩点后,新图是一棵树,因为原图已联通。现在就是要在树上添边,令所有点缩为一个边双联通分量。

    再套路连叶子,答案就是(树上度为1的点数+1)/2。

    3.HDU3394

    题意:有一个公园有n个景点,公园的管理员准备修建m条道路,并且安排一些形成回路的参观路线。如果一条道路被多条道路公用,那么这条路是冲突的;如果一条道路没在任何一个回路内,那么这条路是不冲突的。问分别有多少条有冲突的路和没有冲突的路

    思路:

    首先非多余的边很明显是桥,因为其不在任何一个回路中。

    那么冲突边是多个回路共用的边,注意此处的回路是简单回路,那么考虑点BCC缩点建图,如果一个BCC里的边数大于点数,那么其至少2个环,其中的所有边的都是冲突边。如果点数等于边数,那么只有一个大环,没有冲突变,而点BCC中不存在点数少于边数的情况。

    成功的路并不拥挤,因为大部分人都在颓(笑)
  • 相关阅读:
    Cordova/Cordova.h file not found的解决方法
    使用MethodSwizzle导致按home app进入后台或者app间切换发生crash的解决方法
    基于iOS上MDM技术相关资料整理及汇总
    iOS集成微信支付
    iOS集成支付宝支付
    最新apple邓白氏码申请地址
    游戏的定价
    许久未更,随便侃侃
    记一个有趣的梦
    由《掟上今日子的备忘录》引发的联想
  • 原文地址:https://www.cnblogs.com/SuuT/p/11247343.html
Copyright © 2011-2022 走看看