P3388 【模板】割点(割顶)
P3388 【模板】割点(割顶)
题目背景
割点
题目描述
给出一个 \(n\) 个点,\(m\) 条边的无向图,求图的割点。
输入格式
第一行输入两个正整数 \(n,m\)。
下面 \(m\) 行每行输入两个正整数 \(x,y\) 表示 \(x\) 到 \(y\) 有一条边。
输出格式
第一行输出割点个数。
第二行按照节点编号从小到大输出节点,用空格隔开。
输入输出样例 #1
输入 #1
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出 #1
1
5
说明/提示
对于全部数据,\(1\leq n \le 2\times 10^4\),\(1\leq m \le 1 \times 10^5\)。
点的编号均大于 \(0\) 小于等于 \(n\)。
tarjan图不一定联通。
卡了好久总算过了,首先没有看清输出要求卡了很久,其次就是计算总数时,有的点会被重复遍历,所以计算总数要单开一个循环,最重要的一点就是注意是lowx还是dfsnx,是lowy还是dfsny
#include<iostream>
#include<vector>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m,x,y;
int low[N],dfsn[N],vis[N],cut[N];
vector<int>v[N];
int t=0;
int root;
int cnt=0;
vector<int>ans;
void dfs(int x){
low[x]=dfsn[x]=++t;
int child=0;
for(int y:v[x]){
if(!dfsn[y]){
dfs(y);
child++;
low[x]=min(low[x],low[y]);
if(x==root&&child>=2||x!=root&&low[y]>=dfsn[x])cut[x]=true;
}
else low[x]=min(low[x],dfsn[y]);
}
}
signed main(){
cin>>n>>m;
while(m--){
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
for(int i=1;i<=n;i++)if(!dfsn[i])root=i,dfs(i);
for(int i=1;i<=n;i++) if(cut[i])cnt++;
cout<<cnt<<endl;
for(int i=1;i<=n;i++){
if(cut[i])cout<<i<<" ";
}
return 0;
}

浙公网安备 33010602011771号