「NOIP模拟」建设图【tarjan缩点】

【问题描述】
企鹅国现在准备建设一些新的道路,使得这些新的道路建设完毕之后,可以满足以下条
件——任何一条道路损坏之后,任意两个城市还是可以互相到达。
注意所有的道路都是双向的。
【输入格式】
第一行两个整数 N,M 代表城市个数和原有道路条数。
接下来 M 行,每行 2 个数字 F 和 T,表示从 F 到 T 有一条无向道路。
保证没有自环和重边。保证原有道路可以使得所有城市连通。
【输出格式】
输出一个整数表示最少需要修建的道路数目。


直接缩点。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define db double
#define sg string
#define ll long long
#define rel(i,x,y) for(ll i=(x);i<(y);i++)
#define rep(i,x,y) for(ll i=(x);i<=(y);i++)
#define red(i,x,y) for(ll i=(x);i>=(y);i--)
#define res(i,x) for(ll i=head[x];i;i=nxt[i])
using namespace std;

const ll N=1e5+5;
const ll M=2e5+5;
const ll Inf=1e18;
const db Eps=1e-10;

ll n,m,ans,out[N];
ll cnt=1,to[M<<1],nxt[M<<1],head[N];
ll scc,tim,top,dfn[N],low[N],vis[N],bel[N],size[N],stack[N];

inline ll read() {
	ll x=0;char ch=getchar();bool f=0;
	while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return f?-x:x;
}

void ins(ll x,ll y) {
	to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;
}

void tarjan(ll x,ll f) {
	dfn[x]=low[x]=++tim;stack[++top]=x;
	
	for(ll i=head[x];i;i=nxt[i]) {
		ll y=to[i];
		if(!dfn[y]) tarjan(y,i),low[x]=min(low[x],low[y]);
		else if((i^1)!=f) low[x]=min(low[x],dfn[y]);
	}
	
	if(dfn[x]!=low[x]) return ;
	
	scc++;
	
	while(true) {
		ll y=stack[top--];
		bel[y]=scc;size[scc]++;
		if(x==y) return ;
	}
}

void dfs(ll x) {
	res(i,x) {
		ll y=to[i];
		if(!vis[y]) {
			vis[y]=1;
			if(bel[x]!=bel[y]) out[bel[x]]++;dfs(y);
		}
	}
}

void File() {
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
}

int main() {
	File();
	
	n=read(),m=read();
	
	rep(i,1,m) {
		ll x=read(),y=read();
		ins(x,y);ins(y,x);
	}
	
	tarjan(1,0);
	
	vis[1]=1;
	
	dfs(1);
	
	rep(i,1,scc) if(!out[i]) ans++;
	
	if(out[bel[1]]==1) ans++;
	
	if(ans==1) puts("0");
	else printf("%lld\n",(ans+1)>>1);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/83386800
今日推荐