tarjan割边

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>

using namespace std;

int cnt = 1,l[100005],h[100005],nex[100005];
int num,p,stack[100005],low[100005],dfn[100005];
bool op[100005],op_sig[100005];//op_sig判断路径是否走过 
int f,r,a,b,ans;

inline void add( int v1 , int v2 ) {
	++ cnt;
	l[cnt] = h[v1];
	h[v1] = cnt;
	nex[cnt] = v2;
	
	++ cnt;
	l[cnt] = h[v2];
	h[v2] = cnt;
	nex[cnt] = v1;
}

void tarjan( int now ) {
	dfn[now] = low[now] = ++ num;
	stack[++ p] = now;
	op[now] = true;
	for (int i = h[now]; i != 0; i = l[i]) {
		if( op_sig[i] == false) {
			if ( dfn[nex[i]] == 0 ) {
				op_sig[i] = true;//2^1=3 3^1=2 ......
				op_sig[i^1] = true;//4^1=5 5^1=4... ...
				//标记now到nex[i]的路径已经走过 
				tarjan( nex[i] );
				low[now] = min( low[now] , low[nex[i]] );
				if ( low[nex[i]] > dfn[now] ) {
                                        //只有这种情况是割边
					ans++;
				}
			}
			else {
				if ( op[nex[i]] ) {
					low[now] = min( low[now] , dfn[nex[i]] );
				}
			}
		}
	}
	if ( dfn[now] == low[now] ) {
		int temp;
		do {
			temp = stack[p];
			op[temp] = false;
			p --;
		} while ( now !=temp );
	}
	return;
}

int main() {
	scanf("%d%d",&f,&r);
	for (int i = 1; i <= r; ++i){
		scanf("%d%d",&a,&b);
		add( a , b );
	}
	tarjan( 1 );
	printf("%d\n",ans);
	return 0;
} 
posted @ 2023-03-26 14:59  觉清风  阅读(13)  评论(0编辑  收藏  举报