tarjan——割边与割点

安昙

2018-08-28 17:02:57

Personal

用Dfn数组记录搜索到该点的时间。

Low数组是一个标记数组,记录该点所在的强连通子图所在搜索子树的根节点的Dfn值。

以上是有向图的low、dfn定义,实际上无向图与其类似。

无向图中,dfn[i]表示DFS过程中到达点i的时间,low[i]表示能通过其他边回到其祖先的最早时间

在实际运用之前,先看下列一些定义:

割点:

在一无向连通图内,去掉一点,则该连通图不再连通,则该点被称为割点,一个图可能会有多个割点;

割边:

在一无向连通图内,若删掉某边后,则该连通图不再连通,则该边被称为割边,同理,一个图也可能有多条割边;

一般来说,无向图中的tarjan主要围绕这两个问题进行,而判断割点和割边的方程可以通过low与dfn求出

割点的判定:

原理:

在一棵DFS树中,根root是割点当且仅当它至少有两个儿子,其他点v是割顶当且仅当它有一个儿子u,从u或者u的后代出发没有指向v祖先(不含v)的B边, 则删除v以后u和v的父亲不连通, 故为割点

割点判定算法:

对于DFS树根, 判断度数是否大于1

对于其他点u, 如果不是根的直接儿子,且low[u] >= dfn[P[u]], 则它的父亲v=P[u]是割点

割边的判定:

原理

发现T边(u,v)时若发现v和它的后代不存在一条连接u或其祖先的B边, 则删除(u,v)后u和v不连通, 因此(u,v)为桥

桥的判定算法

发现T边(u, v)时若low[v]>=dfn[u],则(u,v)为桥

注意:以上为无重边情况,当有重边时:

如果让发现该结点的边来更新该节点的low值,则必定会有low[u]=low[v]

所以不能让发现该结点的边来更新该节点的low值,在此条件下,dfn[v]=low[v]时,(u,v)是桥

转载传送门

(1)DFS中,e=uv是父子边,且dfn[u]>1,lowlink[v]≥dfn[u],则u是割点

嗅探器(ZJOI2004)

Description

  某军搞信息对抗实战演习.红军成功地侵入了蓝军的内部网络.蓝军共有两个信息中心.红军计划在某台中间服务器上安装一个嗅探器,从而能够侦听到两个信息中心互相交换的所有信息.但是蓝军的网络相当的庞大,数据包从一个信息中心传到另一个信息中心可以不止有一条通路.现在需要你尽快地解决这个问题.应该把嗅探器安装在哪个中间服务器上才能保证所有的数据包都能被捕获?

Input

  输入文件的第一行一个整数n(1<=n<=100),表示蓝军网络中服务器的数目. 接下来若干行是对蓝军网络的拓扑结构描述. 每行是两个整数i,j表示编号为I和编号为j的两台服务器间存在连接(显然连接是双向的).服务器的编号从1开始.描述一两个0结束. 再接下来一行是两个整数a,b分别表示两个中心服务器的编号.

Output

  输出编号。如果有多个解输出编号最小的一个.如果找不到任何解,输出”No solution”.

Sample Input

5

2 1

2 5

1 4

5 3

2 3

5 1

0 0

4 2

Sample Output

1

代码:

#include<iostream>
#define inf 0x7fffffff/2
using namespace std;
int s,t;
int n;
int sign;
int low[10000];
int dfn[10000];
int prt[10000];
int Map[1000][1000];
int ans=inf;
void dfs(int u)
{
    low[u]=dfn[u]=++sign;
    for(int i=1;i<=n;i++)
    {
        if(Map[u][i]&&prt[u]!=i)
        {
            if(dfn[i]==0)
            {
                prt[i]=u;
                dfs(i);
                low[u]=min(low[u],low[i]);
            }
            else
            {
                low[u]=min(low[u],dfn[i]);
            }
        }
    }
}
void check(int u)
{
    if(u==s)return;
//  system("pause");
    if(low[u]>=dfn[prt[u]]&&prt[u]!=s)
    ans=min(ans,prt[u]);
    check(prt[u]);
}
int main()
{
    cin>>n;
    while(1)
    {
        int tis,tit;
        cin>>tis>>tit;
        if(tis==0&&tit==0)break;
        Map[tis][tit]=Map[tit][tis]=1;
    }
    cin>>s>>t;
    dfs(s);
    check(t);
    if(ans==inf)cout<<"No solution";
    else cout<<ans;
}