Sweety

Practice makes perfect

导航

图基础模板

Posted on 2015-09-02 19:58  蓝空  阅读(173)  评论(0编辑  收藏  举报

1、判断割顶:

对于根节点当然简单,当且仅当它有两个或者是更多的子节点时,他才是割顶。

对于其他节点,

定理:在无向图连通图G的DFS树中,非根节点u是G的割顶当且仅当u存在一个子节点v,使得v及其所有后代都没有反向边连回u的祖先

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>

using namespace std;

const int maxn = 1000;

vector<int> G[maxn];
int pre[maxn], dfs_clock, low[maxn], n; ///访问当前点的顺序标志,dfs_clock表示时间戳,low[v]为v及其后代所能练会的最早的祖先的pre值
bool iscut[maxn];  ///是否为割顶

void init()
{
    for(int i=0; i<n; i++)
        G[i].clear();
    memset(iscut, false, sizeof(iscut));
    memset(pre, 0, sizeof(pre));
    dfs_clock = 0;
}

int dfs(int u, int fa)  //u在DFS树中的父结点是fa   返回u的最小low
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0; //子结点数目
    for(int i=0; i<G[u].size(); i++)
    {
        int v = G[u][i];
        if(!pre[v])     //没有访问过v, 没有必要用vis标记了
        {
            child++;
            int lowv = dfs(v, u);  ///获得子节点最小low
            if(lowv >= pre[u])   iscut[u] = true;
            lowu = min(lowu, lowv); //用后代的 low 函数更新 u 的 low 函数
        }
        else if(pre[v] < pre[u] && v != fa)  //(u,v)为反向边  
            lowu = min( lowu, pre[v] );   //用反向边更新 u 的 low 函数
    } 
    if( fa < 0 && child < 2 )  //根节点当且仅当它有两个或者更多的子节点时才是割顶
        iscut[u] = false;
    low[u] = lowu;
    return lowu;
}

int main()
{
    int m, u, v;
    scanf("%d%d", &n, &m);

    init();

    for(int i=0; i<m; i++)
    {
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }

    for(int i=0; i<n; i++)
        if(!pre[i])
          dfs(i, -1);

    for(int i=0; i<n; i++)  //将割点输出
        if(iscut[i]) 
            printf("%d ", i);
        
    putchar('\n');
    
    return 0;
}

其他重点图基础见:链接