题目描述
设有一棵二叉树,如图:
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在1 处,则距离和 4+12+2×20+2×40=136;若医院建在 33 处,则距离和4×2+13+20+40=81。
输入格式
第一行一个整数 nn,表示树的结点数。
接下来的 nn 行每行描述了一个结点的状况,包含三个整数 w, u, vw,u,v,其中 ww 为居民人口数,uu 为左链接(为 00 表示无链接),vv 为右链接(为 00 表示无链接)。
输出格式
一个整数,表示最小距离和。
输入输出样例
输入 #1复制
5 13 2 3 4 0 0 12 4 5 20 0 0 40 0 0输出 #1复制
81说明/提示
数据规模与约定
对于 100% 的数据,保证1≤n≤100,0≤u,v≤n,1≤w≤10^5。
题意: 有n个小区,每个小区会有一定人数。那么要在n个小区当中设置一个医院,问将医院设置在哪个小区,所有人到医院的路程之和最短。
题解: 如果两个小区相连那么他们之间的距离为一,那么该小区有多少人那么从该小区到下一个小区的距离就是该小区的人数,所以我们只用统计从该小区到医院要经过多少个路段,然后总距离就是当前人数乘以这个路段个数。那么我们把每一个点都设置一次为医院然后确定下来哪个小区为医院,所以我们跑一个堆优化版的Djkstra算法就可以了最后分别遍历起点就是了。
关键就是存图理解这个距离
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define x first
#define y second
//#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10 ;//INF = 1e9 + 10;
int n, m, k;
int h[N], idx;
int dist[N];
bool st[N];
int a[N];
struct Edge{
int nxt, to, d;
}e[N];
void add(int u, int v, int w){
e[++idx].d = w, e[idx].to = v, e[idx].nxt = h[u], h[u] = idx;
}//链式前向星存图
void djkstra(int s)//堆优化版
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[s] = 0;
priority_queue<PII, vector<PII>, greater<PII> > q;
q.push({0, s});
while(!q.empty()){
auto t = q.top();
q.pop();
int sa = t.y, dis = t.x;
if(st[sa]) continue;
st[sa] = true;
for(int i = h[sa]; i; i = e[i].nxt){
int j = e[i].to;
if(dist[j] > dist[sa] + e[i].d){
dist[j] = dist[sa] + e[i].d;
q.push({dist[j], j});
}
}
}
}
signed main()
{
IOS;
cin >> n;
for(int i = 1; i <= n; i ++){
int b, c;
cin >> a[i] >> b >> c;
if(b != 0) add(i, b, 1), add(b, i, 1);//无向图,只要两个小区相连距离为一
if(c != 0) add(i, c, 1), add(c, i, 1);
}
int sum, mi = 3e9 + 10;
for(int i = 1; i <= n; i ++){
djkstra(i);//每一个点为起点
sum = 0;
for(int j = 1; j <= n; j ++){
if(j != i){
sum += dist[j]*a[j];//统计距离,路段数*人数
}
}
mi = min(mi, sum);//取最优解
}
cout << mi << endl;
return 0;
}