P1364
医院设置
题目描述
设有一棵二叉树,如图:
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 \(1\)。如上图中,若医院建在1 处,则距离和 \(=4+12+2\times20+2\times40=136\);若医院建在 \(3\) 处,则距离和 \(=4\times2+13+20+40=81\)。
输入格式
第一行一个整数 \(n\),表示树的结点数。
接下来的 \(n\) 行每行描述了一个结点的状况,包含三个整数 \(w, u, v\),其中 \(w\) 为居民人口数,\(u\) 为左链接(为 \(0\) 表示无链接),\(v\) 为右链接(为 \(0\) 表示无链接)。
输出格式
一个整数,表示最小距离和。
样例 #1
样例输入 #1
5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
样例输出 #1
81
提示
数据规模与约定
对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 100\),\(0 \leq u, v \leq n\),\(1 \leq w \leq 10^5\)。
虽说暴力 Floyd 也能过 但是本质还是 换根DP
别把数组开小了啊啊啊!!!(莫名MLE)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+5;
int n,a[N];
struct Tree {
int nxt,to;
} edge[N];
int head[N],cnt,tot;
inline void add(int u,int v) {
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int dep[N],siz[N],fa[N];
void dfs(int u,int fat) {
dep[u]=dep[fat]+1,fa[u]=fat,siz[u]=a[u];
for(int i=head[u]; i; i=edge[i].nxt) {
int v=edge[i].to;
if(v==fat)continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
int f[N];
void DFS(int u,int fat) { //change root dp
for(int i=head[u]; i; i=edge[i].nxt) {
int v=edge[i].to;
if(v==fat)continue;
f[v]=min(f[v],f[u]+tot-2*siz[v]);
DFS(v,u);
}
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1; i<=n; i++) {
int u,v;
cin>>a[i];
tot+=a[i];
cin>>u>>v;
if(u)add(i,u),add(u,i);
if(v)add(i,v),add(v,i);
}
memset(f,0x3f,sizeof(f));
dfs(1,0);
f[1]=0;
for(int i=2; i<=n; i++)f[1]+=a[i]*(dep[i]-dep[1]);
DFS(1,0);
int minn=INT_MAX;
for(int i=1; i<=n; i++)
minn=min(minn,f[i]);
cout<<minn<<"\n";
return 0;
}