樹
目錄
- 《算法筆記》重點摘要
- 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;
}
- 用參數 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;
}