割点、桥

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long ll;
const double EPS = 1e-8;
const int maxn = 1e2+10;

struct node{
    int to, next;
}edge[maxn*maxn*2];

int cnt, head[maxn];

int idx;//dfs计数 
int dfn[maxn]; //表示dfs遍历到该节点的序号,也就是顺序值
int low[maxn]; //表示当前顶点不通过父亲节点能访问到的祖先节点(父亲节点上面的节点)中的最小顺序值
bool cut[maxn];//是否为割点 

void addEdge(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
//以u为根节点dfs过程中产生一棵搜索树 
void Tarjan(int u, int pre)
{
    dfn[u] = low[u] = ++idx;
    int son = 0;
    for(int i = head[u]; i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre) continue;
        if(!dfn[v])
        {
            son++;
            Tarjan(v, u);
            low[u] = min(low[u] , low[v]);
            //如果u不是树根,且存在儿子v使得dfn(u)<=low(v) 也就是说儿子v无法绕过父亲u到达比父亲时间戳小的点 
            if(u != pre && low[v] >= dfn[u]) cut[u] = true;
            //if(low[v] > dfn[u] ) (u,v)边是桥 
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
	//如果u是树根,并且u不止一个子树 
    if(u == pre && son > 1) cut[u] = true;
}

void init()
{
    cnt = 1;
    memset(head, 0, sizeof(head));
    idx = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(cut, false, sizeof(cut));
}

int main()
{
    int n;
    while(scanf("%d", &n) && n)
    {
        init();
        int u, v;
        while(scanf("%d", &u) && u)
        {
            while(getchar()!='
')
            {
                scanf("%d", &v);
                addEdge(u, v);
                addEdge(v, u);
            }
        }

        Tarjan(1, 1);
        int ans = 0;
        for(int i = 1; i<=n; i++)
            if(cut[i]) ans++;

        printf("%d
", ans);
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>

using namespace std;
typedef long long ll;
const double EPS = 1e-8;
const int maxn = 1e2+10;

int ans;
struct node{
    int to, next;
}edge[maxn*maxn*2];

int cnt, head[maxn];

int idx;//dfs计数 
int dfn[maxn]; //表示dfs遍历到该节点的序号,也就是顺序值
int low[maxn]; //表示当前顶点不通过父亲节点能访问到的祖先节点(父亲节点上面的节点)中的最小顺序值

vector< pair<int ,int > > bridge; 
bool cmp(pair<int ,int > a, pair<int ,int > b){
	if(a.first == b.first) return a.second < b.second;
	return a.first < b.first;
}

void addEdge(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
//以u为根节点dfs过程中产生一棵搜索树 
void Tarjan(int u, int pre)
{
    dfn[u] = low[u] = ++idx;
    for(int i = head[u]; i; i = edge[i].next)
    {
        int v = edge[i].to;
        //if(v == pre) continue;
        if(!dfn[v])
        {
            Tarjan(v, u);
            low[u] = min(low[u] , low[v]);

            if(low[v] > dfn[u] ){ //(u,v)边是桥 
            	bridge.push_back(make_pair(min(u , v) , max(u , v)));
        	}
        } 
        else if(v != pre)
            low[u] = min(low[u], dfn[v]);
    }
}

void init(){
	bridge.clear();
	ans = 0;
    cnt = 1;
    memset(head, 0, sizeof(head));
    idx = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
}

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
    	if(n == 0){
    		printf("0 critical links
");
    		printf("
");
    		continue;
		}
        init();
        int u, v, x;
        for(int i=1; i<=n ;i++){
        	scanf("%d (%d)",&u, &x);
			for(int i=1; i<=x; i++){
				scanf("%d",&v);
				addEdge(u , v);
				addEdge(v , u);
			}
		} 
		for(int i=0; i<n; i++){
			if(!dfn[i]) Tarjan(i, i);
		}
        sort(bridge.begin(), bridge.end(), cmp);
        printf("%d critical links
",bridge.size());
        for(int i=0; i<bridge.size(); i++){
        	printf("%d - %d
",bridge[i].first, bridge[i].second);
		}
		printf("
");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/czsharecode/p/10803186.html