PAT甲級 樹 相關題_C++題解

目錄

  • 《算法筆記》重點摘要
  • 1004 Counting Leaves (30)
  • 1053 Path of Equal Weight (30)
  • 1079 Total Sales of Supply Chain (25)
  • 1090 Highest Price in Supply Chain (25)
  • 1094 The Largest Generation (25)
  • 1106 Lowest Price in Supply Chain (25)

《算法筆記》 9.2 樹的遍歷 重點摘要

1. 常考邊界條件

  • 空樹:沒有結點
  • 樹只有一個根節點時,它亦爲葉子結點

2. 樹的靜態實現

(1) 定義
  • 須要數據域
struct Node{
    typename data;
    int level;
    vector<int> child;
} node[MAXN];
  • 不須要數據域,只須要樹的結構
vector<int> child[MAXN];
(2) 新建結點
int index = 0;
int newNode (int value){
    node[index].data = value;
    node[index].child.clear();
    return index++;
}
(3) 先根遍歷
void preorder (int root){
    printf("%d\n", node[root].data);
    for (int i = 0; i < node[root].child.size(); i++)
        preorder(node[root].child[i]);
}
(4) 層序遍歷
void levelorder(int root){
    queue<int> q;
    q.push(root);
    node[root].level = 0;
    while(!q.empty()){
        int front = q.front();
        printf("%d ", node[front].data);
        q.pop();
        for (int i = 0; i < node[front].child.size(); i++){
            int child = node[front].child[i];
            node[child].level = node[front].level + 1;
            q.push(node[front].child[i]);
        }
    }
}

3. 樹與搜索

  • 合法的 DFS 遍歷過程即樹的先根遍歷過程
  • 合法的 BFS 遍歷過程即樹的層序遍歷過程

1004 Counting Leaves (30)

題目思路:DFS

  • 記錄當前節點的層級和樹的深度,當層級高於深度時,更新樹的深度
  • 若當前節點爲葉結點,對應層級的葉節點數 ++
  • 若非葉結點,遞歸進入其子結點
  • 最後依據樹的深度輸出各層級葉結點數
#include<iostream>
#include<vector>
using namespace std;
vector<int> children[100];
int levelnum[100] = {0}, depth = 1;
void dfs(int index, int level)
{
    if (children[index].empty()){
        levelnum[level]++;
        if (level > depth) depth = level;
    }
    for (int i = 0; i < children[index].size(); i++)
        dfs(children[index][i], level+1);
}
int main()
{
    int n, m, id, k, child;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++){
        scanf("%d%d", &id, &k);
        for (int j = 0; j < k; j++){
            scanf("%d", &child);
            children[id].push_back(child);
        }
    }
    dfs(1,1);
    printf("%d", levelnum[1]);
    for (int i = 2; i <= depth; i++)
        printf(" %d", levelnum[i]);
    return 0;
}

1053 Path of Equal Weight (30)

題目思路:DFS

  • 因爲要按權值輸出,每接收完一個節點的子結點後就對其子結點容器進行排序,這樣保證 DFS 時直接輸出就是從大到小的順序
  • 記錄路徑用 vector,訪問子結點 進入下一層遞歸 DFS 前將其 push_back,從遞歸返回時再 pop_back,繼續壓入這一層下一個子結點
  • sum == weights 時,要判斷當前節點的子結點容器是否爲空,便是否是葉結點,若不是直接 return
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int weights;
vector<int> path;
struct Node{
    int weight;
    vector<int> children;
} node[100];
bool cmp (int a, int b){ return node[a].weight > node[b].weight; }
void DFS(int index, int sumweight)
{
    if (sumweight > weights) return;
    if (sumweight == weights){
        if (!node[index].children.empty()) return;
        for (int i = 1; i < path.size(); i++)
            printf("%d ", node[path[i-1]].weight);
        printf("%d\n", node[path[path.size()-1]].weight);
        return;
    }
    for (int i = 0; i < node[index].children.size(); i++){
        int child = node[index].children[i];
        path.push_back(child);
        DFS(child, sumweight+node[child].weight);
        path.pop_back();
    }
}
int main()
{
    int n, m, id, k, child;
    scanf("%d%d%d", &n, &m, &weights);
    for (int i = 0; i < n; i++) scanf("%d", &node[i].weight);
    for (int i = 0; i < m; i++){
        scanf("%d%d", &id, &k);
        for (int j = 0; j < k; j++){
            scanf("%d", &child);
            node[id].children.push_back(child);
        }
        sort(node[id].children.begin(), node[id].children.end(), cmp);
    }
    path.push_back(0);
    DFS(0, node[0].weight);
    return 0;
}

1079 Total Sales of Supply Chain (25)

題目思路:DFS

  • 樹結點沒有數據域,只要保存供應和售出的子結點關係,用 vector 的數組保存子結點便可
  • 用 map 保存零售商 id 與對應的貨品數量,不須要順序用 unordered_map 便可
  • DFS 用參數 index 和 level 標記當前遍歷的結點的下標和層數
  • 若遇到葉結點,即子結點容器爲空時,從 map 中取出對應的貨品數量,根據層數計算單價,計算此零售商銷售額後加入 sum 值中
  • 遍歷結束後 sum 保存所求值,按要求輸出便可
#include<iostream>
#include<vector>
#include<unordered_map>
#include<cmath>
using namespace std;
vector<int> children[100000];
double sum = 0, price, rate;
unordered_map<int,int> retailer;
void DFS(int index, int level){
    if (children[index].empty())
        sum += price * pow(1 + rate/100, level-1) * retailer[index];
    for (int i = 0; i < children[index].size(); i++)
        DFS(children[index][i], level+1);
}
int main()
{
    int n, k, id, amount;
    scanf("%d%lf%lf", &n, &price, &rate);
    for (int i = 0; i < n; i++){
        scanf("%d", &k);
        if (!k) scanf("%d", &retailer[i]);
        for (int j = 0; j < k; j++){
            scanf("%d", &id);
            children[i].push_back(id);
        }
    }
    DFS(0,1);
    printf("%.1f", sum);
    return 0;
}

1090 Highest Price in Supply Chain (25)

題目思路

  • 樹結點沒有數據域,只要保存供應和售出的子結點關係,用 vector 的數組保存子結點便可
  • DFS 求樹的最大深度和葉結點個數,按要求計算並輸出
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> children[100000];
int depth = 1, leafnum = 0;
void DFS(int index, int level){
    if (level > depth){
        depth = level;
        leafnum = 1;
    }
    else if (level == depth) leafnum++;
    for (int i = 0; i < children[index].size(); i++)
        DFS(children[index][i], level+1);
}
int main()
{
    int n, supplier, root;
    double price, rate;
    scanf("%d%lf%lf", &n, &price, &rate);
    for (int i = 0; i < n; i++){
        scanf("%d", &supplier);
        if (supplier == -1) root = i;
        else children[supplier].push_back(i);
    }
    DFS(root,1);
    printf("%.2f %d\n", price * pow(1 + rate/100, depth-1), leafnum);   
    return 0;
}

1094 The Largest Generation (25)

BFS(層序遍歷)

  • 要記錄每層對應的結點數,在結點中設 level 變量記錄層數,用 vector 記錄子結點的下標
  • 層序遍歷,每層將子結點壓入隊列時爲子結點賦 level 值,彈出隊列時給 level 值對應的數量 ++
  • 最後遍歷記錄每層結點數的 map,找到結點數最多的層輸出
#include<iostream>
#include<unordered_map>
#include<queue>
using namespace std;
struct Node{
    int level;
    vector<int> children;
} node[100];
int main()
{
    int n, m, id, k, child, root = 1, maxnum = 1, maxlevel = 1;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        scanf("%d%d", &id, &k);
        for (int j = 0; j < k; j++){
            scanf("%d", &child);
            node[id].children.push_back(child);
        }
    }
    unordered_map<int,int> levelnum;
    queue<int> q;
    q.push(root);
    node[root].level = 1;
    while (!q.empty()){
        int now = q.front();
        levelnum[node[now].level]++;
        q.pop();
        for (int i = 0; i < node[now].children.size(); i++){
            int child = node[now].children[i];
            q.push(child);
            node[child].level = node[now].level + 1;
        }
    }
    for (auto it: levelnum){
        if (it.second > maxnum){
            maxnum = it.second;
            maxlevel = it.first;
        }
    }
    printf("%d %d\n", maxnum, maxlevel);
    return 0;
}

DFS

  • 用參數 index 和 level 標記當前遍歷的結點的下標和層數
  • 數組 levelnum 標記當前層數 level 所含結點數
  • 最後遍歷一遍 levelnum 數組找出最大值。
#include<iostream>
#include<vector>
using namespace std;
vector<int> children[100];
int levelnum[100] = {0};
void dfs(int index, int level){
    levelnum[level]++;
    for (int i = 0; i < children[index].size(); i++)
        dfs(children[index][i], level+1);
}
int main()
{
    int n, m, id, k, child, maxnum = 1, maxlevel = 1;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        scanf("%d%d", &id, &k);
        for (int j = 0; j < k; j++){
            scanf("%d", &child);
            children[id].push_back(child);
        }
    }
    dfs(1,1);
    for (int i = 1; i < 100; i++){
        if (levelnum[i] > maxnum){
            maxnum = levelnum[i];
            maxlevel = i;
        }
    }
    printf("%d %d\n", maxnum, maxlevel);
    return 0;
}

1106 Lowest Price in Supply Chain (25)

題目思路:DFS

  • 保存最小葉結點的深度 depth,對應深度的葉結點個數 leafnum
  • DFS 遇到葉結點與 depth 比較,若相等將個數 ++,若小於 depth 說明找到了更小的深度,更新 depth,重置 leafnum = 1
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> children[100000];
int depth = 100000;
int leafnum = 0;
void DFS(int index, int level)
{
    if (children[index].empty()){
        if (level == depth) leafnum++;
        else if (level < depth){
            depth = level;
            leafnum = 1;
        }
    }
    for (int i = 0; i < children[index].size(); i++)
        DFS(children[index][i], level+1);
}
int main()
{
    int n, k, child;
    double price, rate;
    scanf("%d%lf%lf", &n, &price, &rate);
    for (int i = 0; i < n; i++){
        scanf("%d", &k);
        for (int j = 0; j < k; j++){
            scanf("%d", &child);
            children[i].push_back(child);
        }
    }
    DFS(0,1);
    printf("%.4f %d", price * pow(1 + rate/100, depth-1), leafnum);
    return 0;
}
相關文章
相關標籤/搜索