题目来源:
https://www.luogu.org/problemnew/show/P3388
题目描述:
题目背景
割点
题目描述
给出一个n个点,m条边的无向图,求图的割点。
输入输出格式
输入格式:
第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
输出格式:
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入样例#1: 复制
6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6
输出样例#1: 复制
1 5
说明
n,m均为100000
tarjan 图不一定联通!!!
解题思路:
模板题,关键就是学习一下tarjan求割点的算法,加深一下理解,感觉现在对tarjan算法的思想有了进一步了解,但是还差点什么,以后补上。。。
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <iomanip>
const int maxn=1000005;
using namespace std;
int low[maxn],dfn[maxn],cut[maxn],tot,ans,n,m;
vector<int>E[maxn];
void tarjan(int u,int fa)
{
int rd=0;
low[u]=dfn[u]=++tot;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i];
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]&&u!=fa)cut[u]=1;
if(u==fa)rd++;
}
low[u]=min(low[u],dfn[v]);
}
if(rd>=2&&u==fa)cut[fa]=1;
}
int main()
{
std::ios::sync_with_stdio(false);
ans=tot=0;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
E[a].push_back(b);
E[b].push_back(a);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i,i);
for(int i=1;i<=n;i++)
if(cut[i])ans++;
cout<<ans<<endl;
for(int i=1;i<=n;i++)
if(cut[i])cout<<i<<" ";
cout<<endl;
return 0;
}