【树的遍历,最短路】Day 2 提高组模拟C组 T4 景点中心

xiaoxiao2021-02-28  39

题目描述

题目大意

给定一张无向图 G=(n,n1) G = ( n , n − 1 ) ,每个点上有一定的人,选定一个点,使得所有人走到那里的代价最小。

解题思路

30分思路 最短路, O(n3) O ( n 3 ) 30~60分思路 最短路 O(n2logn) O ( n 2 l o g n ) 60分思路 从每个点出发 dfs d f s 遍历 O(n2) O ( n 2 ) 100分思路 从1节点出发 dfs d f s 遍历,再根据结果进行递推,复杂度 O(n) O ( n )

100分代码

#include<cstdio> #include<cstring> #define N 100001 #define M 200001 using namespace std; struct node{int next,to,w;}e[M];int l[M],a[N],n,tot,ansi; long long ans=2147483647456465234557ll,f[N],rs[N],jl[N]; bool vis[N]; void add(int u,int v,int w) { e[tot]={l[u],v,w};l[u]=tot++; e[tot]={l[v],u,w};l[v]=tot++; return; } void dfs(int x,int dep)//从1节点遍历 { vis[x]=true; jl[x]=a[x]*dep;rs[x]=a[x];//求出每个节点下面的子树的人数 for(int i=l[x];~i;i=e[i].next) { int y=e[i].to; if(!vis[y]) dfs(y,dep+e[i].w),jl[x]+=jl[y],rs[x]+=rs[y];//加上其子树的值 } } void fdfs(int x,int fa,int w)//dfs转移,表示从第fa节点转移到x节点以及连接它们之间的w { vis[x]=true; if(x!=1) f[x]=f[fa]+rs[1]*w-2*rs[x]*w;//转移一个点,其代价等于其父亲的值加上全部人乘上这条边(全部人都跑过来了),同时要减去这个点下面的人乘这条边乘2(本来是要走的,现在不仅不要走了,所以要减去2倍) if(f[x]<ans) {ans=f[x];ansi=x;}//保存答案 for(int i=l[x];~i;i=e[i].next) { int y=e[i].to; if(!vis[y]) fdfs(y,x,e[i].w);//继续遍历 } } int main() { memset(l,-1,sizeof(l)); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z); dfs(1,0); memset(vis,0,sizeof(vis));//记得清0 f[0]=1e9; f[1]=jl[1]; fdfs(1,0,0); printf("%d\n%lld",ansi,ans); }
转载请注明原文地址: https://www.6miu.com/read-2631070.html

最新回复(0)