拓撲排序·二:有向無環圖,求總的病毒感染數

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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章