赛前板子-割点【洛谷P3388】

注意如果题目要求割点的个数的话,一定不能在tarjan算法中去统计,会导致单个点被重复统计多次,导致答案比实际多。应该在对所有点求完tarjan以后(因为图可能不是联通的),在记录每个点是否是割点的数组中扫描一遍去统计。

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
const int N=20100,M=201010;
inline int read(){
	register int v=0,sign=0; char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') break;
	if(ch=='-') sign=1; else v=ch-48;
	while(isdigit(ch=getchar())) v=v*10+ch-48;
	if(sign==1) return -v; else return v;
}
int nxt[M],to[M],head[N],len;
inline void addedge(int a,int b){
	nxt[++len]=head[a]; head[a]=len; to[len]=b;
}
int n,m,ans;
int nowroot,dfn[N],tme,low[N];
bool isgedian[N];
void tarjan(int v){
	dfn[v]=low[v]=++tme;
	int cnt=0;
	for(int i=head[v];i!=-1;i=nxt[i]){
		int u=to[i];
		if(!dfn[u]){
			cnt++;
			tarjan(u);
			low[v]=min(low[v],low[u]);
			if((v==nowroot&&cnt>1)||(v!=nowroot&&low[u]>=dfn[v])) isgedian[v]=true;
			//不可以直接在这里统计割点个数 !!!因为循环的缘故,一个点可能会被计算多次,导致个数错误 
		}else low[v]=min(low[v],dfn[u]);

	}
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	rep(i,1,m){
		int a,b;
		cin>>a>>b;
		addedge(a,b); addedge(b,a); 
	}
	rep(i,1,n) if(!dfn[i]) nowroot=i,tarjan(i);
	rep(i,1,n) if(isgedian[i]) ans++; 
	cout<<ans<<endl;
	rep(i,1,n) if(isgedian[i]) cout<<i<<' ';
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值