洛谷 2341受欢迎的牛

洛谷  2341受欢迎的牛

废话真多啊,就是tarjan一遍,缩强连通分量点,建好新的图之后查看是否有出度为0的点。

如果有且仅有一个,那么这一个一定是可以被所有牛喜欢的啦,用cnt数组去记录每一个强连通分量中点的个数,这个可以被所有点到达的强连通分量中点的个数就是answer!

但这只有85分;

因为如果有两个或两个以上出度为0的点,他们是绝对不可能互相到达的了!必须判断是否有且仅有1个出度为0的分量,否则输出0!

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=10000+5; 
vector<int> olg[N];
vector<int> reg[N];
stack<int> s;
int seq,num,n,m,a,b,tmp1,tmp2,ans,ok;
int dfn[N],low[N],belong[N],ind[N],cnt[N];
bool ins[N];
void tarjan(int x){                     //tarjan的板子
	int j;
	dfn[x]=low[x]=++seq;
	s.push(x);ins[x]=true;
	for(int i=0;i<olg[x].size();i++){
		j=olg[x][i];
		if(!dfn[j]){
			tarjan(j);
			low[x]=min(low[x],low[j]);
		}
		else if(ins[j]) low[x]=min(low[x],dfn[j]);
	}
	if(dfn[x]==low[x]){
		++num;
		while(s.top()!=x){
			cnt[num]++;
			belong[s.top()]=num;
			ins[s.top()]=false;
			s.pop();
		}
		cnt[num]++;
		belong[x]=num;
		ins[x]=false;
		s.pop();
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){        //建旧图;
		scanf("%d%d",&a,&b);
		olg[a].push_back(b);
	}
	for(int i=1;i<=n;i++)
	    if(!dfn[i])      //没找过的点也许不与任何tarjan跑过的点连接,所以要再跑一次,不从不漏!
	        tarjan(i);
	for(int i=1;i<=n;i++){       //建新图;
		tmp1=belong[i];
		for(int j=0;j<olg[i].size();j++){
			tmp2=belong[olg[i][j]];
			if(tmp1!=tmp2){
				reg[tmp1].push_back(tmp2);
			}
		}
	}
	for(int i=1;i<=num;i++)
	    if(!reg[i].size()){       //新图中出度为0的点
	    	ok++;                 //判断是否只有一个
	        ans+=cnt[i];
	    }
	    
	if(ok==1)                      //出度为0的只有一个
		cout<<ans;
	else                           //出度为0的分量有一个以上的话
	    cout<<0;
	return 0;
}
/*
6 7
1 2
2 1
1 4
3 4
6 4
4 5
5 6
*/
tarjan越来越顺手了!加油!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值