题目描述
设有一棵二叉树,如图:
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在1 处,
输入格式
第一行一个整数 n,表示树的结点数。
接下来的 n 行每行描述了一个结点的状况,包含三个整数 w, u, v,其中 w 为居民人口数,u 为左链接(为 0 表示无链接),v 为右链接(为 0 表示无链接)。
输出格式
一个整数,表示最小距离和。
输入输出样例
输入 #1
5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
输出 #1
81
说明/提示
数据规模与约定
思路:
这题数据很小,只要可行的方法基本都可以过。
(直接连接的两点的距离都看作1)
bfs: 每个点出发都走一遍bfs,更新最小点
floyed:先找出每两个点的最短距离,然后也是for一遍,更新最小点
代码一(BFS):
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=110;
struct node{ //v是点的编号,step是距离
int v,step;
node(int a,int b){v=a;step=b;}
};
vector<int> g[maxn]; //邻接表
int n,u,v,w[maxn],ans=1<<27; //w数组记录点权,ans初始值为很大的数
int bfs(int s) //bfs代码
{
int sum=0;
queue<node> q;
bool inq[maxn]={false}; //记录是否入过队
inq[s]=1;
q.push(node(s,1)); //放入起点
while(!q.empty())
{
int u=q.front().v;
int step=q.front().step;
q.pop();
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!inq[v])
{
inq[v]=1;
q.push(node(v,step+1)); //下一层为当前step +1
sum += w[v]*step; //累加值
}
}
}
return sum;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i]>>u>>v;
if(u) g[i].push_back(u),g[u].push_back(i); //无向图
if(v) g[i].push_back(v),g[v].push_back(i);
}
for(int i=1;i<=n;i++) //for一遍,找出最小值
ans=min(ans,bfs(i));
cout<<ans;
return 0;
}
代码二(Floyed):
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=110;
const int inf=1<<27; //很大的数
int dis[maxn][maxn]; //记录两点距离
int n,u,v,w[maxn],ans=inf; //w为点权
int main()
{
fill(dis[0],dis[0]+maxn*maxn,inf); //初始化为很大的值
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i]>>u>>v;
if(u) dis[i][u]=dis[u][i]=1; //直接相连的两点距离为1
if(v) dis[i][v]=dis[v][i]=1;
}
for(int k=1;k<=n;k++) //过一遍floyed
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dis[i][k]<inf && dis[k][j]<inf)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
for(int i=1;i<=n;i++) //找出最小值
{
int sum=0;
for(int j=1;j<=n;j++)
if(i!=j) sum += w[j]*dis[i][j];
ans =min(ans,sum);
}
cout<<ans;
return 0;
}