CSP 201709-4 通訊網路(DFS,BFS)兩種解法
技術標籤:csp
201709-4
問題描述
某國的軍隊由N個部門組成,為了提高安全性,部門之間建立了M條通路,每條通路只能單向傳遞資訊,即一條從部門a到部門b的通路只能由a向b傳遞資訊。資訊可以通過中轉的方式進行傳遞,即如果a能將資訊傳遞到b,b又能將資訊傳遞到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個部門都存在的部門的數量”
解題思路
題中所描述的是兩個部門的單向關係(即a向b傳遞資訊)。但實際上a與b的關係是雙向關係(即相互知曉對方的存在)。
由此我們不難想到建立一個二維陣列儲存各個點(部門)的關係。若某個點(部門)與其他所有點(部門)都有關係即是所求點。
資料結構
對於圖的資料結構,我們最熟悉的就是鄰接矩陣。但在此題中,一個點(部門)可能與多個點(部門)有聯絡。連結矩陣難以處理這樣的問題。所以我們選擇鄰接表,鄰接表通常用連結串列實現,但對於這道演算法題顯然有些小題大做。好在c++的stl的vector
可以有效的解決這個問題。(具體實現見程式碼)演算法分析
我們需要遍歷所有的點(部門)來儲存它們的關係,可以使用DFS或BFS來實現。
此題提供了兩種實現(BFS,DFS)的程式碼。
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);
}
}