买房子

本文介绍了一种寻找城市中最佳购房位置的算法解决方案。通过构建树状结构来模拟城市区域间的连接关系,利用两次深度优先搜索(DFS)算法确定距离所有其他区域总距离最短的购房区域数量及具体总距离。

买房子

Time Limit: 10000MS Memory Limit: 65536K

Description

有天小C突发奇想,自己是不是也该考虑一下买房子的问题了。小C所在的城市被划分成n个区域,这n个区域是连通的,并且从任意一个区域到达另外区域的方案数只有一种。现在这n个区域都有房卖,小C想,如果他要选择买房区域的话,他所在的区域到其他的区域的距离总和应该最小。现在告诉你n个区域的连接情况,请你帮他算算,有多少个区域满足要求?

Input

输入第一行,一个整数n;
接下来n-1行,每行三个整数a,b,c,表示连接区域a和b的路长为c,其中0<=a,b< n,0< c<=10000。

Output

输出满足条件的区域数和最小的距离总和。

Sample Input

6
0 1 1
1 5 1
1 2 2
2 3 1
2 4 1

Sample Output

2 10

Hint

对于40%的数据,1< n<=200;
对于60%的数据,1< n<=2000;
对于100%的数据,1< n<=20000;

思路

对于一棵树想要求出其到任意一点的距离很简单

void pro_dfs(int x,int f){
    cnt[x]=1;
    for(int i=0;i<G[x].size();i++){
        int c=G[x][i].c,t=G[x][i].t;
        if(t==f)continue;
        pro_dfs(t,x);
        cnt[x]+=cnt[t];
        pro[x]+=pro[t]+1ll*c*cnt[t];
        //将子节点的信息返回给父节点
    }
}

于是通过一次dfs就求出了第一个ans
那么其他点的ans怎么求呢
可以通过从父节点转移上来

void re_dfs(int x,int f){
    for(int i=0;i<G[x].size();i++){
        int c=G[x][i].c,t=G[x][i].t;
        if(t==f)continue;
        sum[t]=sum[x]-1ll*(cnt[t]*c)+1ll*c*(n-cnt[t]);
        //将根的信息给子 
        re_dfs(t,x);
    }
}

思考

1.对于树上遍历的问题不仅仅拘泥于父节点到子节点,也可以先求出父节点再向下转移
2.类似该类需要求出所以解的问题,可以求出一个解再进行转移

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long LL;
const int M=20005;
struct node{int t,c;};
vector<node>G[M];
int cnt[M],n,num,a,b,c;
LL sum[M],pro[M],mi=2e20;
bool mark[M];
void pro_dfs(int x,int f){
    cnt[x]=1;
    for(int i=0;i<G[x].size();i++){
        int c=G[x][i].c,t=G[x][i].t;
        if(t==f)continue;
        pro_dfs(t,x);
        cnt[x]+=cnt[t];
        pro[x]+=pro[t]+1ll*c*cnt[t];
    }
}
void re_dfs(int x,int f){//将根的信息给子 
    for(int i=0;i<G[x].size();i++){
        int c=G[x][i].c,t=G[x][i].t;
        if(t==f)continue;
        sum[t]=sum[x]-1ll*(cnt[t]*c)+1ll*c*(n-cnt[t]);
        re_dfs(t,x);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d%d",&a,&b,&c);
        G[a].push_back((node){b,c});
        G[b].push_back((node){a,c});
    }pro_dfs(0,-1);
    sum[0]=pro[0];
    re_dfs(0,-1);
    for(int i=0;i<n;i++){
        if(sum[i]==mi)num++;
        if(sum[i]<mi)num=1,mi=sum[i];
    }
    cout<<num<<' '<<mi<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值