_YueYang

导航

targan解析

【算法讲解】

先咕了(

【例题】

【例1】牛的舞会

模板题,求强连通分量个数。
code:

#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
int head[25000],cnt;
int dfn[25000],low[25000],tot,vis[25000],vis1[25000],stk[25000],top;
struct edge{
	int v,next;
}e[55000];
void add(int u,int v){
	e[++cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void dfs(int u){
	dfn[u]=low[u]=++tot;
	vis[u]=vis1[u]=1;stk[++top]=u;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(!dfn[v])dfs(v),low[u]=min(low[u],low[v]);
		else if(vis[v])low[u]=min(low[u],low[v]);
	}
	if(dfn[u]==low[u]){
		int sum=0;
		while(stk[top]!=u)vis[stk[top]]=0,--top,++sum;
		--top;++sum;
		if(sum>1)++ans;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(int i=1;i<=n;++i)
		if(vis1[i]==0)dfs(i);
	printf("%d\n",ans);
	return 0;
}

【例2】受欢迎的牛G

缩点,把所有强连通分量都缩成一个点,使其成为一张有向无环图,则最受欢迎的点即为出度为 \(0\) 的点。
当然,不是真的让你把几个点缩成一个点,只要你判断一下是不是出度为 \(0\) 。另外,还得考虑一下该图是否联通。具体见代码。
code:

using namespace std;
int n,m,ans;
int head[25000],cnt;
int dfn[25000],low[25000],tot,vis[25000],vis1[25000],stk[25000],top;
int node[25000],cot;
int out[25000],sum[25000],num;
int d[25000];
struct edge{
	int v,next;
}e[55000];
void add(int u,int v){
	e[++cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int find(){
	int pot=0;
	for(int i=1;i<=cot;++i)
		for(int j=head[node[i]];j;j=e[j].next)
			if(d[e[j].v]==0)++pot;//求出度
	return pot;
}
void dfs(int u){
	dfn[u]=low[u]=++tot;
	vis[u]=1;stk[++top]=u;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(dfn[v]==0)dfs(v),low[u]=min(low[u],low[v]);
		else if(vis[v])low[u]=min(low[u],dfn[v]);
	}//以上为tarjan正常操作
	if(dfn[u]==low[u]){
		++num;
		int t;
		do{
			t=stk[top--];
			node[++cot]=t;//缩点。储存是为了方便求出度。
			vis[t]=0;
			++sum[num];//强连通图的点的个数
			d[t]=1;//标记是否在强连通图上
		}
		while(t!=u);
		out[num]=find();
		cot=0;
		memset(d,0,sizeof(d));
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(int i=1;i<=n;++i)
		if(dfn[i]==0)dfs(i);
	int c=0;
	for(int i=1;i<=num;++i)
		if(out[i]==0)++c,ans=sum[i];
	if(c==1)printf("%d\n",ans);
	else printf("0\n");//别忘了判断联通!
	return 0;
}

posted on 2021-07-03 23:00  _YueYang  阅读(120)  评论(0编辑  收藏  举报