题目大意:
给定一棵n个结点的树,求一个点x作为根,使得所有结点到x的距离和最小。
思路:
树形DP。
首先考虑将1作为根的情况。
很显然我们可以用一遍O(n)的DFS预处理出每个结点所对应子树大小size和子树内每个结点到这个结点的距离和sum。
这样也就相当于我们递推求出了以1作为根时各结点到它的距离和。
现在考虑将根往下转移。
假设我们现在要从u转移到v,那么显然在sum[u]的基础上,sum[v]需要变化的是(u,v)之间的连接的边。
也就是说sum[y]=sum[x]+n-size[y]*2。
这样我们就可以用O(n)时间将根往下转移。
总的时间复杂度还是O(n)的。
1 #include<cstdio> 2 #include<cctype> 3 typedef long long int64; 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=1000001; 12 int head[N],to[N<<1],next[N<<1],sz; 13 inline void add_edge(const int &u,const int &v) { 14 to[++sz]=v; next[sz]=head[u]; head[u]=sz; 15 to[++sz]=u; next[sz]=head[v]; head[v]=sz; 16 } 17 int64 sum[N],max; 18 int n,size[N],root; 19 void dfs(const int &x,const int &par) { 20 size[x]=1; 21 for(int i=head[x];i;i=next[i]) { 22 const int &y=to[i]; 23 if(y==par) continue; 24 dfs(y,x); 25 size[x]+=size[y]; 26 sum[x]+=sum[y]+size[y]; 27 } 28 } 29 void move(const int &x,const int &par) { 30 if(sum[x]>max) { 31 max=sum[x]; 32 root=x; 33 } else if(sum[x]==max&&x<root) { 34 root=x; 35 } 36 for(int i=head[x];i;i=next[i]) { 37 const int &y=to[i]; 38 if(y==par) continue; 39 sum[y]=sum[x]+n-size[y]*2; 40 move(y,x); 41 } 42 } 43 int main() { 44 n=getint(); 45 for(register int i=1;i<n;i++) { 46 add_edge(getint(),getint()); 47 } 48 dfs(1,0); 49 move(1,0); 50 printf("%d ",root); 51 return 0; 52 }