Tarjan求割点
深度优先生成树记录时间戳和回退戳
// Problem:
// P3388 【模板】割点(割顶)
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3388
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
const int INF=0x3f3f3f3f;
typedef long long ll;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return f*x;
}
const int N=20005;
std::vector<int> edge[N];
int t; //时间戳
bool iscut[N]; //是割点
int dfn[N]; //每个点的时间戳
int low[N]; //每个点的能回退到的最早的时间戳
int cnt;
int root;
void dfs(int u,int fa){
dfn[u]=low[u]=++t; //初始时间戳
int child=0; //儿子数量 深度优先搜索生成树
for(auto v : edge[u]){
if(!dfn[v]){ //这个点没被访问过
++child;
dfs(v,u);
low[u]=std::min(low[u],low[v]); //用后代的low值更新自己的low值
if(low[v]>=dfn[u] && u!=root){
cnt+=!iscut[u]; //这个点在之前可能已经有儿子无法回退
iscut[u]=true; //存在一个后代无法回退到更早的祖先,这个u点就是割点
}
}
else if(v!=fa) low[u]=std::min(low[u],dfn[v]); //不能是low[v] 反例看末尾图片
}
if(u==root && child>1){ //根节点的儿子数超过1个
cnt+=!iscut[u]; //就说明在前面的儿子都无法访问到后面的儿子
iscut[u]=true;
}
}
int main(){
int n=read(),m=read();
while(m--){
int u=read(),v=read();
edge[u].push_back(v);
edge[v].push_back(u);
}
fore(i,1,n+1)
if(!dfn[i]){
root=i;
dfs(i,0);
}
std::cout<<cnt<<endl;
fore(i,1,n+1)
if(iscut[i]) std::cout<<i<<' ';
return 0;
}
割边
其实是需要把dfs中判断割点的代码改一下,这道题有重边,所以edge的second是边的编号
// Problem:
// P1656 炸铁路
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1656
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
const int INF=0x3f3f3f3f;
typedef long long ll;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return f*x;
}
const int N=165;
std::vector<std::pair<int,int>> edge[N];
struct node{
int u;
int v;
};
std::vector<node> ans;
int dfn[N];
int low[N];
int t;
int g[N][N];
bool cmp(const node& a,const node& b){
if(a.u!=b.u) return a.u<b.u;
return a.v<b.v;
}
void dfs(int u,int fa){
low[u]=dfn[u]=++t;
for(auto v:edge[u])
if(!dfn[v.fi]){
dfs(v.fi,v.se);
low[u]=std::min(low[u],low[v.fi]);
if(low[v.fi]>dfn[u] && g[u][v.fi]==1) ans.push_back({std::min(u,v.fi),std::max(u,v.fi)});
}
else if(v.se!=fa) low[u]=std::min(low[u],dfn[v.fi]);
}
int main(){
int n=read(),m=read();
fore(i,1,m+1){
int u=read(),v=read();
g[u][v]++;
g[v][u]++;
edge[u].push_back({v,i});
edge[v].push_back({u,i});
}
dfs(1,0);
sort(ans.begin(),ans.end(),cmp);
// fore(i,1,n+1) std::cout<<dfn[i]<<' '<<low[i]<<endl;
for(auto nd:ans) std::cout<<nd.u<<' '<<nd.v<<endl;
return 0;
}