P2002 消息扩散

题目背景

本场比赛第一题,给个简单的吧,这 100 分先拿着。

题目描述

有n个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出n个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有n个城市都得到消息。

输入输出格式

输入格式:

 

第一行两个整数n,m表示n个城市,m条单向道路。

以下m行,每行两个整数b,e表示有一条从b到e的道路,道路可以重复或存在自环。

 

输出格式:

 

一行一个整数,表示至少要在几个城市中发布消息。

 

输入输出样例

输入样例#1: 复制

5 4
1 2
2 1
2 3
5 1

输出样例#1: 复制

2

说明

【数据范围】

对于20%的数据,n≤200;

对于40%的数据,n≤2,000;

对于100%的数据,n≤100,000,m≤500,000.

【限制】

时间限制:1s,内存限制:256M

【注释】

样例中在4,5号城市中发布消息。、

 

题意:很明显的一个tarjan+缩点,直接套模板,然后输出缩点后入度为0的点的个数,注意在输入的过程中避免成环,应该先来一个判定,其余代码如下

 

#include<iostream>
using namespace std;
const int maxn = 500010;
int n, m, cnt = 1, a, b, index, sum, total, ans;
int dfn[maxn], low[maxn], belong[maxn], indu[maxn], vis[maxn], Stack[maxn], head[maxn];

struct Node{
	int to;
	int next;
}node[2 * maxn];

void add(int u, int v) {
	node[cnt].to = v;
	node[cnt].next = head[u];
	head[u] = cnt++;
}


void tarjan(int u) {
	dfn[u] = low[u] = ++total;
	Stack[++index] = u;
	vis[u] = 1;
	for (int i = head[u]; i != 0; i = node[i].next) {
		int v = node[i].to;
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if (vis[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]) {
		++sum;
		do {
			int p = Stack[index--];
			vis[p] = 0;
			belong[p] = sum;
		} while (Stack[index + 1] != u);
	}
}


int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		cin >> a >> b;
		if (a != b) add(a, b);
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i]) tarjan(i);
	}
	for (int i = 1; i <= n; i++) {
		for (int j = head[i]; j != 0; j = node[j].next) {
			int v = node[j].to;
			if (belong[v] != belong[i]) {
				indu[belong[v]]++;
			}
		}
	}
	for (int i = 1; i <= sum; i++) {
		if (!indu[i]) ans++;
	}
	cout << ans << endl;
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值