拓扑排序·二:有向无环图,求总的病毒感染数

http://hihocoder.com/problemset/problem/1175

举个例子,假设切断部分网络连接后学校网络如下图所示,由4个节点和4条链接构成。最开始只有节点1上有病毒。

最开始节点1向节点2和节点3传送了病毒,自身留有1个病毒:

其中一个病毒到达节点2后,向节点3传送了一个病毒。另一个到达节点3的病毒向节点4发送自己的拷贝:

当从节点2传送到节点3的病毒到达之后,该病毒又发送了一份自己的拷贝向节点4。此时节点3上留有2个病毒:

最后每个节点上的病毒为:

小Hi和小Ho根据目前的情况发现一段时间之后,所有的节点病毒数量一定不会再发生变化。那么对于整个网络来说,最后会有多少个病毒呢?

提示:拓扑排序的应用

输入

第1行:3个整数N,M,K,1≤K≤N≤100,000,1≤M≤500,000

第2行:K个整数A[i],A[i]表示黑客在节点A[i]上放了1个病毒。1≤A[i]≤N

第3..M+2行:每行2个整数 u,v,表示存在一条从节点u到节点v的网络链接。数据保证为无环图。1≤u,v≤N

输出

第1行:1个整数,表示最后整个网络的病毒数量 MOD 142857

样例输入
4 4 1
1
1 2
1 3
2 3
3 4
样例输出
6
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

#define MOD 142857

int N, M, K;//全局变量是因为solve()中没有定义。
vector<vector<int>> graph;
vector<int> inDegree;
vector<int> virus;
int m, u, v;

void solve() {//拓扑排序 严蔚敏182页算法介绍
	int res = 0;
	queue<int> que;//队列存放入度为0的节点。
	for (int i = 1; i <= N; ++i)  if(inDegree[i] == 0)  que.push(i);
	
	while (!que.empty()) {
		int u = que.front();//获得 队首元素
		que.pop();//删除 队首元素
		for (unsigned int i=0;i<graph[u].size();i++) {
			int v=graph[u][i];//取出graph[u]中的第i个元素v,如graph[1]={2,3};
			virus[v] += virus[u];//virus[v=2]=virus[v=2]+virus[u=1]。
			virus[v] %= MOD;
			--inDegree[v];//因为删了起点u=1,所以终点v=1的入度减1.
			if (inDegree[v] == 0) que.push(v);
		}//for end
	}//while end

	for (unsigned int i=0;i<virus.size();i++) {
		res += virus[i];//遍历所有节点,求病毒总数。
		res %= MOD;
	}
	//cout <<"res=" << res << endl;
	cout << res << endl;
}

int main() {
	// cout <<"请输入:" << endl;
	while (cin >> N >> M >> K) {
		graph.assign(N + 1, vector<int>());//N+1因为腾出0不用,用u作为第一个下标。
		virus.assign(N + 1, 0);//assign初始化全0.
		inDegree.assign(N + 1, 0);
		for (int i = 0; i < K; ++i) {
			cin >> m;
			virus[m] = 1;//表示黑客在节点m上放了1个病毒
		}
		for (int i = 0; i < M; ++i) {
			cin >> u >> v;//从起点u到终点v.
			graph[u].push_back(v);//起点u对应的终点向量是graph[u]。
			++inDegree[v];//节点v入度加1.
		}
		solve();
	}
	system("pause");
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值