targin 模板 洛谷受欢迎的牛|【模板】强连通分量

57 篇文章 0 订阅

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

输入格式

 第一行:两个用空格分开的整数:N和M

 第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

输出格式

 第一行:单独一个整数,表示明星奶牛的数量

输入输出样例

输入 #1复制

3 3
1 2
2 1
2 3

输出 #1复制

1

说明/提示

只有 3 号奶牛可以做明星

【数据范围】

10%的数据N<=20, M<=50

30%的数据N<=1000,M<=20000

70%的数据N<=5000,M<=50000

100%的数据N<=10000,M<=50000

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 1e5+3;
int head[maxn*20], dfn[maxn], low[maxn];//dfn是时间戳low是最小的时间戳head头
int chudu[maxn], rudu[maxn], id[maxn], all[maxn];//id是染色后的点 all是染色的点数 
bool instal[maxn];int cnt, tot, gg;//instal是判断在不在栈中
stack<int>s;
struct Edge{
	int next, to;
}edge[maxn*20];//链式前向星存图
inline void add(int x, int y) {
	cnt++;
	edge[cnt].to = y;
	edge[cnt].next = head[x];
	head[x] = cnt;	
}
void init() {
	while(!s.empty()) {
		s.pop();
	}
	gg = 0;
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(instal, false, sizeof(instal));
	memset(all, 0, sizeof(all));
	memset(chudu, 0, sizeof(chudu));
	memset(id, 0, sizeof(id));
}
//链式前向星加边
void targin(int x) {
	dfn[x] = low[x] = ++cnt;
	s.push(x);
	instal[x] = true;
	for(int i = head[x];i;i = edge[i].next) {
		int u = edge[i].to;
		if(!dfn[u]) {
			targin(u);
			low[x] = min(low[x], low[u]);
		}
		else if(instal[u]) low[x] = min(low[x], dfn[u]);
	}
	int k;
	if(low[x] == dfn[x]) {
		++gg;
		do{
			k = s.top();s.pop();
			instal[k] = false;
			id[k] = gg;all[gg]++;//id是染色gg是第一次的点把所有的一个联通快的点缩成这个点all是存的缩点的点的数量
		}while(x != k);
	}
}//强连通
 
int main() {
	int n , m;
	while(~scanf("%d%d", &n, &m)) {
		init();
		int a, b;
		for(register int i = 1;i <= m;++i) {
			scanf("%d%d", &a, &b);
			add(a, b);
		} 
		for(register int j = 1;j <= n;++j) {
			if(!dfn[j]) {
				targin(j);
			}
		}
		for(register int i = 1;i <= n;++i) {
			for(int j = head[i];j;j = edge[j].next) {
				int u = edge[j].to;
				if(id[i] != id[u]) {
					chudu[id[i]]++;
				}	
			}
		}
		int tt = 0;
		for(register int i = 1;i <= gg;++i) {
			if(!chudu[i]) {
				if(tt) {
					puts("0");return 0;
				}
				tt = i;
			}//如果入度为0且点数有两个就没有明星牛因为两个以上的点不能连接所以没有如果低于两个就求出入度为1的点的缩点数既是这个联通快数就是明星牛的所有
		}
		printf("%d\n", all[tt]);		
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-lyslyslys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值