题目描述
设有一棵二叉树,如图:
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在 11 处,则距离和 =4+12+2×20+2×40=136=4+12+2×20+2×40=136;若医院建在 33 处,则距离和 =4×2+13+20+40=81=4×2+13+20+40=81。
输入格式
第一行一个整数 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说明/提示
数据规模与约定
对于 100% 的数据,保证 1≤n≤100,0≤u,v≤n,1≤w≤105。
代码:
1.图论
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
bool vis[1000010];//标记数组,标记是否走过某点
int sn[1000010];//存每个点人数
int sum=0,maxx=1e7;//maxx代表minn
vector<int > e[1000010];//存树
void dfs(int now,int dep){
vis[now]=1;//标记走过now这个点
sum+=sn[now]*(dep-1);//根节点深度为1,求和时*(dep-1)
for(auto spot:e[now]){//spot代表e[now]中的每一个值
if(vis[spot]==0) dfs(spot,dep+1);//如果spot这个点没被访问过,深搜
}
}
signed main(){
cin >> n;
for(int i =1;i<=n;i++){
int a,b;
cin >>sn[i]>> a >> b;
if(a!=0) e[i].push_back(a),e[a].push_back(i);
if(b!=0) e[i].push_back(b),e[b].push_back(i);//存双向边
}
for(int i = 1;i<=n;i++){
sum=0;//sum每次初始化为0
for(int j = 1;j<=n;j++){
vis[j]=0;
}//把所有节点初始化为未访问过
dfs(i,1);//把i当根节点重新画图,不受图的影响
if(maxx>sum) maxx=sum;//找最小距离
}
cout << maxx;
return 0;
}
/*
1 ; 4
2 3 ; 3
4 5 ; 1 5
; 2
*/
2.最短路 floyd
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
int sn[1010];//记录每个点人数
int dis[1010][1010];//记录某两点之间最短路径
int minn=1e18;//最小值初始化为一个极大值
signed main(){
cin >> n;
for(int i = 1;i<=n;i++){//初始化
for(int j = 1;j<=n;j++){
dis[i][j]=1e18;
if(i==j) dis[i][j]=0;
}
}
for(int i = 1;i<=n;i++){
int b,c;
cin >> sn[i];
cin >> b >> c;
if(b) dis[i][b]=dis[b][i]=1;//存图
if(c) dis[i][c]=dis[c][i]=1;
}
for(int k = 1;k<=n;k++){//floyd
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i = 1;i<=n;i++){//i代表医院建在某处
int sum=0;
for(int j = 1;j<=n;j++){//j代表某点
sum+=dis[j][i]*sn[j];
}
minn=min(minn,sum);//得较小值
}
cout << minn;
return 0;
}