Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
设有一棵二叉树,如图:
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 1。如上图中,若医院建在1 处,则距离和 =4+12+2×20+2×40=136;若医院建在 3处,则距离和 =4×2+13+20+40=81。
来源:洛谷 www.luogu.com.cn/problem/P13…
输入格式
第一行一个整数 n,表示树的结点数。
接下来的 n 行每行描述了一个结点的状况,包含三个整数 w, u, v,其中 w 为居民人口数,u 为左链接(为 0 表示无链接),v 为右链接(为 0 表示无链接)。
5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
输出格式
一个整数,表示最小距离和。
81
二、思路分析:
我觉得这题最大的困难就是数据的存取,如何去判断1处和4处的距离。我们可以像图中的二叉树一样,保存一个节点的左右节点,确定了医院建在a处后,再通过a的下级一直往下找,直到找到所有结点。
这里使用二维数组存储数据, b[i][k] = b[k][i] = true 表示 i结点 和 k结点 是相邻接点之间的距离为 1,由于图中每个结点都有可能是根节点(医院建的位置),所以相邻接点之间是无向连接。 使用 a[]数组存放每个结点的居民人口数。
我们的大概思路就是把医院建在每个结点都尝试一下,然后取最小距离和的那次, 使用队列进行搜索,由于走了这条路b[i][j] (从i结点走去j结点) 就不能让它走回来了(不然就会死循环),所以我们需要改变 b[j][i] = false 。由于我们要尝试所有的结点为医院,我们每次都需要恢复存储数据,这里我设置每次visit复制b的内容去操作。
三、AC 代码:
import java.util.*;
public class Main {
static int min = Integer.MAX_VALUE, N;
public static void main(String[] args) {
Scanner sr = new Scanner(System.in);
Queue<Po> r = new LinkedList<Po>();
N = sr.nextInt();
int[] a = new int[N + 1];
// b[i][j] = true 表示是相邻结点
boolean[][] b = new boolean[N + 1][N + 1];
boolean[][] visit = new boolean[N + 1][N + 1];
for (int i = 1; i <= N; i++)
{
// a[] 居民人口数
a[i] = sr.nextInt();
for (int j = 0; j < 2; j++) {
int k = sr.nextInt();
// 不是0表示 有左/右结点
if (k != 0) {
b[i][k] = true;
b[k][i] = true;
}
}
}
// 若医院建在i处
for (int i = 1; i < N + 1; i++)
{
int sum = 0;
// new Po(i, 1) : i 的左右结点与医院的距离 为 1
r.add(new Po(i, 1));
copy(b, visit);
while (!r.isEmpty()) {
Po t = r.poll();
// 找其他结点
for (int j = 1; j < N + 1; j++) {
if (visit[t.z][j]) {
// 不能返回(会死循环)
visit[j][t.z] = false;
sum += a[j] * t.count;
// 下一级结点与医院的距离要 +1
r.add(new Po(j, t.count + 1));
}
}
}
if (sum < min)
min = sum;
}
System.out.println(min);
}
// 重新恢复存储数据
static void copy(boolean[][] b, boolean[][] visit) {
for (int i = 1; i < N + 1; i++)
for (int j = 1; j < N + 1; j++)
visit[i][j] = b[i][j];
}
}
class Po {
int z;
int count;
public Po(int z, int count) {
this.z = z;
this.count = count;
}
}
四、总结:
我们可以把这个结点图看做一颗二叉树(实际上它好像就是一颗二叉树....),但是这个二叉树的根节点不一定,我们将这个二叉树以二维数组的形式保存起来,这里保存我们设置无向,但确定医院的位置后,我们搜索遍历的过程中把它变成有向,使它不会造成死循环。通过比较获取最小距离和输出