Tarjan算法
持续补充
首先适用于无向图
在强连通分量中已经得到了每一个点的low、dfn,
输入指向关系的顺序不同得到的每个点的dfn[]、low[]的值不同,(遍历到的次序不同),然后观察,
发现
- 割点
(u为当前点v为下一个相邻的点)当dfn[u] <= low[v]
时当前的节点u为一个割点
分析:v为子树,然后low[v] >= dfn[u] 代表子树不存在一个路径可以时他到达u的祖先,所以u以及u一下的v……这个整体可以组成一个块,所以u是割点
//
// main.cpp
// tarjan_求割点
//
// Created by 陈冉飞 on 2019/8/16.
// Copyright © 2019 陈冉飞. All rights reserved.
//
//#include<bits/stdc++.h>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 100086;
struct node {
int y, net;
}e[maxn << 1];
int lin[maxn], len = 0;
int n, m, root, num = 0;
int dfn[maxn], low[maxn];
bool cut[maxn];
inline int read() {
int x = 0, y = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * y;
}
inline void insert(int xx, int yy) {
e[++len].y = yy;
e[len].net = lin[xx];
lin[xx] = len;
}
void tarjan(int x) {
dfn[x] = low[x] = ++num;
int flag = 0;
for(int i = lin[x]; i; i = e[i].net) {
int to = e[i].y;
if(!dfn[to]) {
tarjan(to);
low[x] = min(low[x], low[to]);
if(low[to] >= dfn[x]) {
flag++;
if(x != root || flag > 1) cut[x] = true;
}
}
else low[x] = min(low[x], dfn[to]);
}
}
int main() {
n = read(), m = read();
len = 1;
for(int i = 1; i <= m; ++i) {
int x, y;
x = read(), y = read();
if(x == y) continue;
insert(x, y);
insert(y, x);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) {
root = i;
tarjan(i);
}
//输出dfn low
for (int i = 1; i <= n; i++) cout<<i<<" "<<dfn[i]<<" "<<low[i]<<endl;
for(int i = 1; i <= n; ++i)
if(cut[i])
cout << i << ' ';
cout << "are cut-vertexes" << '\n';
return 0;
}
裸的求割点的应用、板题、poj1144
注意这个题输入的时候有点奇怪,在输入这个点所有的相连接的边的时候用一个getchar() != '\n'
来判断是否到头,然后再输入和这个点相邻的所有其他点。
其他的直接套求割点的板子就好
//
// main.cpp
// 无向图求割点_poj1144
//
// Created by 陈冉飞 on 2019/8/20.
// Copyright © 2019 陈冉飞. All rights reserved.
//
//#include<bits/stdc++.h>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 100086;
struct node {
int y, net;
}e[maxn << 1];
int lin[maxn], len = 0;
int n, root, num = 0,p,q,ans;
int dfn[maxn], low[maxn];
bool cut[maxn];
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
inline void insert(int xx, int yy) {
e[++len].y = yy;
e[len].net = lin[xx];
lin[xx] = len;
}
void tarjan(int x) {
dfn[x] = low[x] = ++num;
int flag = 0;
for(int i = lin[x]; i; i = e[i].net) {
int to = e[i].y;
if(!dfn[to]) {
tarjan(to);
low[x] = min(low[x], low[to]);
if(low[to] >= dfn[x]) {
flag++;
if(x != root || flag > 1) cut[x] = true;
}
}
else low[x] = min(low[x], dfn[to]);
}
}
int main() {
while (scanf("%d",&n) && n) {
cl(lin,0);cl(dfn, 0);cl(low, 0);cl(cut, 0);ans = 0;num = 0;len = 0;
while (scanf("%d",&p) && p) {
while (getchar() != '\n') {
scanf("%d",&q);
insert(p, q);insert(q, p);
}
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) {
root = i;
tarjan(i);
}
for(int i = 1; i <= n; ++i)
if(cut[i]) ans++;
cout<<ans<<endl;
}
return 0;
}
- 割边
当dfn[u] < low[v]
**时(u,v)为割边,分析见割点。
在这里插入代码片