洛谷P1364医院设置

题目描述

设有一棵二叉树,如图:

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 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;
}

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值