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;
}
posted @ 2023-04-25 23:33  N0zoM1z0  阅读(2)  评论(0编辑  收藏  举报