1. 程式人生 > 實用技巧 >P1364 醫院設定

P1364 醫院設定

floyd

用floyd求出任意一個兩個點之間的最短距離,然後算一下以所有節點為根的情況下的距離之和最小值。
複雜度:\(O(n^3)\)

#include<iostream>
#include<cstring>

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n;
int g[N][N];
int w[N];

int main(){
    memset(g, 0x3f, sizeof g);
    
    cin >> n;
    
    for(int i = 1; i <= n; i ++){
        int a, b;
        cin >> w[i] >> a >> b;
        g[i][a] = g[i][b] = g[a][i] = g[b][i] = 1;
    }
    
    for(int i = 1; i <= n; i ++) g[i][i] = 0;
    
    for(int k = 1; k <= n; k ++)
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
                
    int res = INF;
    
    for(int i = 1; i <= n; i ++){
        int ans = 0;
        for(int j = 1; j <= n; j ++)
            if(i != j) ans += g[i][j] * w[j];
        
        res = min(res, ans);
    }
    
    cout << res;
                
    return 0;
}

樹的重心

需要預處理出:

  1. 以一個結點為整棵樹的根u(這個可以任選,這裡選1,這個和後面的遞推起點有關)的情況下,以每一個結點v為根的子樹包括的所有人口s[v]
  2. 將醫院建在1號點時的總距離f(1)

遞推方法:\(f[v] = f[u] - s[v] + s[1] - s[v];\),f[k]表示把醫院建在k的總距離,s[k]表示包括k在內的以k為根的子樹。
解釋:
v為u的出邊所到達的點,現在已知將醫院建在u時的總距離f[u], 既然v為u的出邊,那麼以v為根的子樹(包括v)本來是走到u的而現在只需要到v,那麼就先需要將f[u]減去s[v], 而除去v的子樹的所有節點(包括v)原本是要走到u的,而現在需要走到v,那麼f[u]還需要加上s[1] (總人口) - s[v]

複雜度:\(O(n)\)

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

struct Node{
    int l, r;
    int w;
}tr[N];

int n;
int s[N];
int f[N];
int level[N];

int dfs_1(int u){
    if(u == 0) return 0;
    s[u] += dfs_1(tr[u].l) + dfs_1(tr[u].r) + tr[u].w;
    return s[u];
}


void dfs_2(int u){
    int l = tr[u].l, r = tr[u].r;
    if(l){
        f[l] = f[u] - s[l] + s[1] - s[l];
        dfs_2(l);
    }
    
    if(r){
        f[r] = f[u] - s[r] + s[1] - s[r];
        dfs_2(r);
    }
}


int main(){
    cin >> n;
    
    for(int i = 1; i <= n; i ++){
        int l, r, w;
        cin >> w >> l >> r;
        
        tr[i] = {l, r, w};
    }
    
    dfs_1(1);
    
    memset(f, 0x3f, sizeof f);
    
    queue<int> q;
    
    q.push(1);
    level[1] = 0;
    f[1] = 0;
    
    while(q.size()){
        int h = q.front();
        q.pop();
        
        int l = tr[h].l, r = tr[h].r;
        level[l] = level[r] = ++ level[h];
        if(l) f[1] += tr[l].w * level[l], q.push(l);
        if(r) f[1] += tr[r].w * level[r], q.push(r);
    }
    
    dfs_2(1);
    
    int res = INF;
    
    for(int i = 1; i <= n; i ++) res = min(res, f[i]);
    
    cout << res;
    
    return 0;
}