洛谷題單指南-二叉樹-P1364 醫院設定

江城伍月發表於2024-03-15

原題連結: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;
}

相關文章