PAT甲級 圖的遍歷 相關題_C++題解

圖的遍歷

PAT (Advanced Level) Practice 圖的遍歷 相關題ios

目錄

  • 《算法筆記》重點摘要
  • 1021 Deepest Root (25)
  • 1076 Forwards on Weibo (30)

《算法筆記》 10.3 圖的遍歷 重點摘要

1. 定義

  • 邊 兩端能夠是 相同 的頂點
  • 能夠把 無向圖 看成全部 邊 都由 正向 和 負向 兩條 有向邊 組成
  • 頂點的:與該頂點相連的邊的條數
  • 頂點和邊量化的屬性分別成爲點權邊權

2. 存儲

2.1 鄰接矩陣
  • G[i][j] 存放邊權,不存在的邊設邊權爲0、-1 或 一個很大的數
  • 鄰接矩陣只適用於頂點數目不太大(通常不超過 1000)的題目
2.2 鄰接表
  • 若只存放每條邊的終點編號,vector 元素類型定義爲 int 便可
vector<int> Adj[N];
Adj[u].push_back(v);
  • 若同時存放終點編號和邊權,可創建結構體,vector 元素類型定義爲結構體
struct Node{
    int v;
    int weight;
};
vector<Node> Adj[N];
Adj[u].push_back({v,weight});

3. DFS

若已知給定圖爲連通圖,則只需一次 DFS 便可完成遍歷算法

const int MAXV = 1000;
const INF = 1000000000;
3.1 鄰接矩陣
int n, G[MAXV][MAXV];
bool vis[MAXV] = {false};
void DFS(int u, int depth){
    vis[u] = true;
    // 若須要對 u 進行一些操做,在這裏進行
    for (int v = 0; v < n; v++)
        if (!vis[v] && G[u][v] != INF)
            DFS(v, depth + 1);
}
void DFSTrave(){
    for (int u = 0; u < n; u++)
        if (!vis[u])
            DFS(u, 1);
}
3.2 鄰接表
vector<int> Adj[MAXV];
int n;
bool vis[MAXV] = {false};
void DFS(int u, int depth){
    vis[u] = true;
    // 若須要對 u 進行一些操做,在這裏進行
    for(int i = 0; i < Adj[u].size(); i++){
        int v = Adj[u][i];
        if (!vis[v])
            DFS(v, depth + 1);
    }
}
void DFSTrave(){
    for (int u = 0; u < n; u++)
        if (!vis[u])
            DFS(u,1);
}

4. BFS

4.1 鄰接矩陣
int n, G[MAXV][MAXV];
bool inq[MAXV] = {false};
void BFS(int u){
    queue<int> q;
    q.push(u);
    inq[u] = true;
    while (!q.empty()){
        int u = q.front();
        q.pop();
        for (int v = 0; v < n; v++){
            if (!inq[v] && G[u][v] != INF){
                q.push(v);
                inq[v] = true;
            }
        }
    }
}
void BFSTrave(){
    for (int u = 0; u < n; u++)
        if (!inq[u])
            BFS(u);
}
4.2 鄰接表
vector<int> Adj[MAXN];
int n;
bool inq[MAXN] = {false};
void BFS(int u){
    queue<int> q;
    q.push(u);
    inq[u] = true;
    while (!q.empty()){
        int u = q.front();
        q.pop();
        for (int i = 0; i < Adj[u].size(); i++){
            int v = Adj[u][i];
            if (!inq[v]){
                q.push(v);
                inq[v] = true;
            }
        }
    }
}
void BFSTrave(){
    for (int u = 0; u < n; u++)
        if (!inq[u])
            BFS(u);
}
4.3 輸出結點層號(鄰接表)
struct Node{
    int v;
    int level;
};
vector<Node> Adj[N];
void BFS(int s){
    queue<Node> q;
    Node start = {s,0};
    q.push(start);
    inq[start.v] = true;
    while(!q.empty()){
        Node now = q.front();
        q.pop();
        int u = now.v;
        for (int i = 0; i < Adj[u].size(); i++){
            Node next  = Adj[u][i];
            next.level = now.level + 1;
            if (!inq[next.v]){
                q.push(next);
                inq[next.v] = true;
            }
        }
    }
}

1021 Deepest Root (25)

題目思路

  • 邊爲雙向,鄰接表法注意兩個方向都要存儲
  • 先按正常 DFS 遍歷一遍,記錄連通份量個數
  • 若不爲樹(份量個數 > 1),直接按要求輸出份量個數便可
  • 若爲樹(份量個數 = 1),分別以每一個結點爲根結點進行 DFS,記錄這樣遍歷樹的深度,與最大深度比較
    • 相等則將此根壓入根集合中
    • 若大於最大深度,說明找到了更大深度,將以前的根集合清空,壓入新發現的根結點
#include<iostream>
#include<vector>
#include<set>
using namespace std;
set<int> roots;
vector<int> Adj[10001];
int n, components = 0, depth = 0, maxdepth = 0;
bool vis[10001] = {false};
void DFS(int root, int level){
    vis[root] = true;
    if (level > depth) depth = level;
    for (int i = 0; i < Adj[root].size(); i++)
        if (!vis[Adj[root][i]])
            DFS(Adj[root][i], level+1);
}
void DFSTrave(){
    for (int i = 1; i < n + 1; i++){
        if (!vis[i]){
            DFS(i, 0);
            components++;
        }
    }
    if (components == 1){
        for (int i = 1; i < n + 1; i++){
            fill(vis, vis+10001, false);
            depth = 0;
            DFS(i,0);
            if (depth == maxdepth) roots.insert(i);
            else if (depth > maxdepth){
                maxdepth = depth;
                roots.clear();
                roots.insert(i);
            }
        }
    }
}
int main()
{
    int u, v;
    scanf("%d", &n);
    for (int i = 1; i < n; i++){
        scanf("%d%d", &u, &v);
        Adj[u].push_back(v);
        Adj[v].push_back(u); 
    }
    DFSTrave();
    if (components > 1) printf("Error: %d components\n", components);
    else for (auto it: roots) printf("%d\n",it);
    return 0;
}

1076 Forwards on Weibo (30)

題目思路:帶層數的廣度優先

  • 用 Node 結構體同時保存 id 和 level
  • 用 inq 記錄結點是否入隊過,入隊過不能重複入隊(重複轉發消息)
  • 記錄結點層數,若超過要求的最高層數也不可再入隊
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct Node{
    int id, level;
};
int maxlevel, numforward;
vector<Node> Adj[1001];
void BFS(int start){
    bool inq[1001] = {false};
    queue<Node> q;
    q.push({start,0});
    inq[start] = true;
    while (!q.empty()){
        Node now = q.front();
        q.pop();
        for (int i = 0; i < Adj[now.id].size(); i++){
            Node next = Adj[now.id][i];
            next.level = now.level + 1;
            if (!inq[next.id] && next.level <= maxlevel){
                inq[next.id] = true;
                q.push(next);
                numforward++;
            }
        }
    }
}
int main()
{
    int n, m, followed, k, query;
    scanf("%d%d", &n, &maxlevel);
    for (int i = 1; i < n + 1; i++){
        scanf("%d", &m);
        for (int j = 0; j < m; j++){
            scanf("%d", &followed);
            Adj[followed].push_back({i,0});
        }
    }
    scanf("%d", &k);
    for (int i = 0; i < k; i++){
        scanf("%d", &query);
        numforward = 0;
        BFS(query);
        printf("%d\n", numforward);
    }
    return 0;
}
相關文章
相關標籤/搜索