原題連結:https://www.luogu.com.cn/problem/P1364
題意解讀:醫院的位置使所有居民所走的路程之和為最小,即找到一個節點,該節點到其他所有節點的距離*其他節點的權值即人數之和最小。
解題思路:
看起來是一個二叉樹問題,本質上是一個圖論問題,有三種方式可以求解:
1、計算每兩個節點之間的最短路徑(Floyd演算法),然後列舉在每一個點建醫院,計算所有居民的路程之和,求最小值。
2、從每一個節點出發,進行BFS搜尋,搜尋過程中計算每個點到起始點的路程*人數,求和,對和取最小值。
3、方法同2,只不過採用DFS搜尋。
既然在二叉樹板塊,就採用二叉樹的方式處理
要實現從每一個節點出發進行BFS或者DFS,需要儲存每個節點的子節點、父節點資訊
struct node
{
int weight; //人口數
int sub[3]; //sub[0]父節點、sub[1]左子節點、sub[2]右子節點
} tree[N];
下面給出DFS版本的程式碼,因為個人感覺DFS程式碼更簡潔(但BFS程式碼沒有遞迴更容易理解)。
100分程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
struct node
{
int weight; //人口數
int sub[3]; //sub[0]父節點、sub[1]左子節點、sub[2]右子節點
} tree[N];
bool flag[N];
int n, w, u, v;
int sum, ans = INT_MAX;
//idx是節點號,當前節點距離起始節點路徑長度depth,路程和sum
void dfs(int idx, int depth)
{
flag[idx] = true;
if(depth > 0) sum += tree[idx].weight * depth;
for(int i = 0; i < 3; i++)
{
if(!flag[tree[idx].sub[i]]) dfs(tree[idx].sub[i], depth + 1);
}
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> w >> u >> v;
tree[i].weight = w;
tree[i].sub[1] = u;
tree[i].sub[2] = v;
if(u) tree[u].sub[0] = i; //記錄u的父節點為i
if(v) tree[v].sub[0] = i; //機率v的父節點為i
}
for(int i = 1; i <= n; i++)
{
sum = 0; //路程之和初始化
memset(flag, 0, sizeof(flag)); //flag初始化為false
dfs(i, 0);
ans = min(ans, sum);
}
cout << ans;
return 0;
}