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;
}
原文地址:https://www.cnblogs.com/tomori/p/13862891.html