Codeforces - Mr. Kitayuta's Technology

题目链接:Codeforces - Mr. Kitayuta’s Technology


我们可以发现如果联通块存在环,若环的大小为n,那么最少必然需要n条边。

如果不存在环,我们对于每一个联通块最少必然需要n-1条边。

所以我们对每个联通块判环然后分别计数即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,scc[N],vis[N],num[N],low[N],dfn[N],cnt,res,co,mark[N],f[N];
vector<int> g[N];	stack<int> st;
void Tarjan(int x){
	low[x]=dfn[x]=++cnt,vis[x]=1,st.push(x);
	for(auto to:g[x]){
		if(!dfn[to]){
			Tarjan(to);	low[x]=min(low[x],low[to]);
		}else if(vis[to])	low[x]=min(low[x],dfn[to]);
	}
	if(low[x]==dfn[x]){
		co++;	int u;
		do{
			u=st.top();	vis[u]=0; scc[u]=co; num[co]++; st.pop();
			if(num[co]>1)	mark[co]=1;
		}while(u!=x);
	}
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
signed main(){
	cin>>n>>m;
	for(int i=1,a,b;i<=m;i++)	cin>>a>>b,g[a].push_back(b);
	for(int i=1;i<=n;i++)	if(!dfn[i])	Tarjan(i);
	for(int i=1;i<=co;i++)	f[i]=i;
	for(int i=1;i<=n;i++)
		for(auto to:g[i]){
			int x=find(scc[i]),y=find(scc[to]);
			if(x^y)	f[x]=y,num[y]+=num[x],mark[y]|=mark[x];
		}
	for(int i=1;i<=co;i++)	if(find(i)==i){
		if(mark[i])	res+=num[i];
		else	res+=num[i]-1;
	}
	cout<<res;
	return 0;
}
发布了553 篇原创文章 · 获赞 242 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104249398