【问题描述】
设有一棵二叉树,如图5-1:
131
/
24 123
/
420 405
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为l。如上图中,若医院建在:
【输入】
第一行一个整数n,表示树的结点数。(n≤100)
接下来的n行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为0表示无链接;第三个数为右链接。
【输出】
一个整数,表示最小距离和。
【样例】
hospital.in hospital.out
5 81
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
【知识准备】
图的遍历和最短路径。
【算法分析】
本题的求解任务十分明了:求一个最小路径之和。
根据题意,对n个结点,共有n个路径之和:用记号Si表示通向结点i的路径之和,则,其中Wj为结点j的居民数,g(i,j)为结点j到结点i的最短路径长度。下面表中反映的是样例的各项数据:
j g(i,j) i |
1 |
2 |
3 |
4 |
5 |
Si |
1 |
0 |
1 |
1 |
2 |
2 |
0×13+1×4+1×12+2×20+2×40=136 |
2 |
1 |
0 |
2 |
3 |
3 |
1×13+0×4+2×12+3×20+3×40=217 |
3 |
1 |
2 |
0 |
1 |
1 |
1×13+2×4+0×12+1×20+1×40=81 |
4 |
2 |
3 |
1 |
0 |
2 |
2×13+3×4+1×12+0×20+2×40=130 |
5 |
2 |
3 |
1 |
2 |
0 |
2×13+3×4+1×12+2×20+0×40=90 |
从表中可知S3=81最小,医院应建在3号居民点,使得所有居民走的路径之和为最小。
由此可知,本题的关键是求g[i,j],即图中任意两点间的最短路径长度。
求任意两点间的最短路径采用下面的弗洛伊德(Floyd)算法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define M 110 #define INF 999999 using namespace std; int f[M][M],a[M],dis[M],n; int main() { freopen("jh.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=INF; for(int i=1;i<=n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); a[i]=x; f[i][y]=f[y][i]=1; f[i][z]=f[z][i]=1; } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j&&j!=k&&i!=k) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) dis[i]+=f[i][j]*a[j]; sort(dis+1,dis+n+1); printf("%d",dis[1]); return 0; }