买房子
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 1Sample 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;
}