1. 程式人生 > 其它 >CSP 201709-4 通訊網路(DFS,BFS)兩種解法

CSP 201709-4 通訊網路(DFS,BFS)兩種解法

技術標籤:csp

201709-4

問題描述

某國的軍隊由N個部門組成,為了提高安全性,部門之間建立了M條通路,每條通路只能單向傳遞資訊,即一條從部門a到部門b的通路只能由ab傳遞資訊。資訊可以通過中轉的方式進行傳遞,即如果a能將資訊傳遞到bb又能將資訊傳遞到c,則a能將資訊傳遞到c。一條資訊可能通過多次中轉最終到達目的地。
    由於保密工作做得很好,並不是所有部門之間都互相知道彼此的存在。只有當兩個部門之間可以直接或間接傳遞資訊時,他們才彼此知道對方的存在。部門之間不會把自己知道哪些部門告訴其他部門。
 在這裡插入圖片描述
    上圖中給了一個4個部門的例子,圖中的單向邊表示通路。部門1可以將訊息傳送給所有部門,部門4可以接收所有部門的訊息,所以部門1和部門4知道所有其他部門的存在。部門2和部門3之間沒有任何方式可以傳送訊息,所以部門2和部門3互相不知道彼此的存在。

    現在請問,有多少個部門知道所有N個部門的存在。或者說,有多少個部門所知道的部門數量(包括自己)正好是N

輸入格式

輸入的第一行包含兩個整數N, M,分別表示部門的數量和單向通路的數量。所有部門從1到N標號。
    接下來M行,每行兩個整數a, b,表示部門a到部門b有一條單向通路。

輸出格式

輸出一行,包含一個整數,表示答案。

樣例輸入

4 4
1 2
1 3
2 4
3 4

樣例輸出

2

樣例說明

部門1和部門4知道所有其他部門的存在。

資料規模

對於30%的評測用例,1 ≤ N ≤ 10,1 ≤ M ≤ 20;
    對於60%的評測用例,1 ≤ N ≤ 100,1 ≤ M

≤ 1000;
    對於100%的評測用例,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000。

分析

題目要求

“知道所有N個部門都存在的部門的數量”

解題思路

題中所描述的是兩個部門的單向關係(即ab傳遞資訊)。但實際上ab的關係是雙向關係(即相互知曉對方的存在)。

由此我們不難想到建立一個二維陣列儲存各個點(部門)的關係。若某個點(部門)與其他所有點(部門)都有關係即是所求點。

資料結構

對於圖的資料結構,我們最熟悉的就是鄰接矩陣。但在此題中,一個點(部門)可能與多個點(部門)有聯絡。連結矩陣難以處理這樣的問題。所以我們選擇鄰接表,鄰接表通常用連結串列實現,但對於這道演算法題顯然有些小題大做。好在c++的stl的vector

可以有效的解決這個問題。(具體實現見程式碼)

演算法分析

我們需要遍歷所有的點(部門)來儲存它們的關係,可以使用DFSBFS來實現。

此題提供了兩種實現(BFSDFS)的程式碼。

AC程式碼

BFS

//BFS
#include<bits/stdc++.h>
using namespace std;
void clearq(queue<int>& q) {
	queue<int> empty;
	swap(empty, q);
}
int main() {
	int n, m;
	cin >> n >> m;
	
	vector<vector<int> > G(n+1, vector<int>());
	vector<vector<bool> > matrix(n + 1, vector<bool>(n + 1, false));
	
	int a, b;
	for (int i = 0; i < m; i++) {//輸入
		cin >> a >> b;
		G[a].push_back(b);
	}

	vector<bool> vis;
	queue<int> q;
	for (int i = 1; i <= n; i++) {//對每一個點都進行BFS
		clearq(q);
		vis = vector<bool>(n + 1, false);
		q.push(i);
		vis[i] = true;
		while (!q.empty()) {//BFS主體
			int v = q.front();
			matrix[i][v] = true;//儲存
			matrix[v][i] = true;//關係
			q.pop();

			vis[v] = true;
			int size = G[v].size();
			for (int j = 0; j < size; j++) {
				if (!vis[G[v][j]]) {
					q.push(G[v][j]);
					vis[G[v][j]] = true;
				}
			}
		}
	}
	int count = 0;

	for (int i = 1; i <= n; i++) {
		int sum = 0;
		for (int j = 1; j <= n; j++) {
			sum += matrix[i][j];
		}
		if (sum == n)//若與所有點都有關係,計數器加1;
			count++;
	}
	cout << count;
	return 0;
}

DFS

//DFS
#include<bits/stdc++.h>
using namespace std;
void dfs(int i);
int n, m, ths;
vector<vector<bool> > matrix;//此程式碼的DFS以遞迴實現,所以變數大多使用全域性變數
vector<vector<int> > G;
vector<bool> vis;

int main() {
	cin >> n >> m;
	G = vector<vector<int> >(n + 1, vector<int>());
	matrix = vector<vector<bool> >(n + 1, vector<bool>(n + 1, false));

	int a, b;
	for (int i = 0; i < m; i++) {
		cin >> a >> b;
		G[a].push_back(b);
	}
	
	for (int i = 1; i <= n; i++) {
		vis = vector<bool>(n + 1, false);//新一輪的遍歷,初始化vis陣列
		ths = i;
		dfs(i);
	}

	int count = 0;
	for (int i = 1; i <= n; i++) {
		int sum = 0;
		for (int j = 1; j <= n; j++) {
			sum += matrix[i][j];
		}
		if (sum == n)
			count++;
	}
	cout << count;
	return 0;
}
void dfs(int i) {
	if (vis[i]) { return; }
	vis[i] = true;
	int size = G[i].size();
	matrix[i][ths] = true;// 儲存
	matrix[ths][i] = true;// 關係

	for (int j = 0; j < size; j++) {//向子節點深入
		int u = G[i][j];
		dfs(u);
	}
}