枚举医院节点并在树上 BFS 计算到各点距离,按人口加权后取总和最小值。
OJ: luogu
题目 ID: P1364
难度:普及/提高-
标签:树BFS枚举python
日期: 2026-07-16 18:17
题意
树上每个节点有居民数。选择一个节点建医院,代价是所有节点人口乘到医院距离之和,求最小代价。
思路
n<=100,直接枚举医院位置。对每个候选点 BFS 求到全树距离,再计算:
树中两点路径唯一,BFS 第一次到达的层数就是边数距离。取所有候选代价的最小值即可。
Python 知识
- 邻接表用列表推导式创建,每条父子边双向加入。
map(total_distance,range(1,n+1))产生每个候选医院的代价,min直接聚合。deque与距离列表完成单源 BFS。/home/rainboy/mycode/hugo-blog/content/program_language/python/bfs_shortest.md:树也可视为无权图进行 BFS。/home/rainboy/mycode/hugo-blog/content/program_language/python/map_reduce_filter.md:命名函数与map/min组合。
代码
python
import sys
from collections import deque
input = sys.stdin.buffer.readline
n = int(input())
population = [0] * (n + 1)
tree = [[] for _ in range(n + 1)]
for node in range(1, n + 1):
weight, left, right = map(int, input().split())
population[node] = weight
for child in (left, right):
if child:
tree[node].append(child)
tree[child].append(node)
def total_distance(start):
distance = [-1] * (n + 1)
distance[start] = 0
queue = deque([start])
total = 0
while queue:
node = queue.popleft()
total += population[node] * distance[node]
for neighbor in tree[node]:
if distance[neighbor] == -1:
distance[neighbor] = distance[node] + 1
queue.append(neighbor)
return total
print(min(map(total_distance, range(1, n + 1))))cpp
/**
* P1364 医院设置
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-27 00:00
* update_at: 2026-07-27 00:00
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;
// 邻接表建无向树
int head[MAXN], to[MAXN * 2], nxt[MAXN * 2], edge_cnt;
int w[MAXN]; // 各结点人口数
int n;
void add_edge(int u, int v) {
++edge_cnt;
to[edge_cnt] = v;
nxt[edge_cnt] = head[u];
head[u] = edge_cnt;
}
// BFS 求从 start 出发到所有点的距离总和
int bfs(int start) {
int dist[MAXN];
memset(dist, -1, sizeof(dist));
dist[start] = 0;
queue<int> q;
q.push(start);
int sum = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
sum += w[u] * dist[u]; // 人口 × 距离
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (dist[v] == -1) {
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
return sum;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int l, r;
scanf("%d%d%d", &w[i], &l, &r);
if (l) { add_edge(i, l); add_edge(l, i); }
if (r) { add_edge(i, r); add_edge(r, i); }
}
int ans = INF;
for (int i = 1; i <= n; ++i) ans = min(ans, bfs(i));
printf("%d\n", ans);
return 0;
}复杂度
每个候选 BFS 为 n 个候选,总时间
总结
小规模优化题先考虑直接枚举候选并准确计算代价;树的唯一路径让每次 BFS 很简单。
