<题目链接>
题目大意:
给你一棵树,任意去除某一个点后,树被分成了几个联通块,则该点的平衡值为所有分成的连通块中,点数最大的那个,问你:该树所有点中,平衡值最小的那个点是什么?
解题分析:
运用DFS,找到以u为根节点,所有子节点数的最大值,然后求出这些最大值的最小值。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int MAXN = 2e4+7; 7 struct Edge{ 8 int to,next; 9 }edge[MAXN*2]; //注意这里要*2,因为要存双向边 10 11 int head[MAXN],tot; 12 void init(){ 13 memset(head,-1,sizeof(head)); 14 tot = 0; 15 } 16 void addedge(int u,int v){ 17 edge[tot].to = v;edge[tot].next = head[u]; 18 head[u] = tot++; 19 } 20 int dp[MAXN],num[MAXN]; 21 int n; 22 23 void dfs(int u,int pre){ 24 dp[u] = 0;num[u] = 1; 25 for(int i = head[u];i != -1;i = edge[i].next){ 26 int v = edge[i].to; 27 if(v == pre)continue; //如果下一个点是u的父亲(即刚刚走过的点),那么跳过,防止下一步dfs(v,u)遍历该无向图时,不停的在两个点之间来回遍历 28 dfs(v,u); //继续从它的子节点开始向下搜索 29 dp[u] = max(dp[u],num[v]); //dp[u]指的是u的每个子节点方向所对应的最大节点数的最大值 30 num[u] += num[v]; 31 } 32 //num[u]此时代表除父节点方向外的所有子节点数(包括它本身,,因为num[u]初始化为1) 33 dp[u] = max(dp[u],n - num[u]); //n-num[u]指的是dp[u]父节点方向的节点数 34 } 35 36 int main(){ 37 int T;scanf("%d",&T); 38 int u,v; 39 while(T--){ 40 scanf("%d",&n); 41 init(); 42 for(int i = 1;i < n;i++){ 43 scanf("%d%d",&u,&v); 44 addedge(u,v);addedge(v,u); 45 } 46 dfs(1,-1); 47 int loc=-1,ans=1e9; 48 for(int i=1;i<=n;i++){ 49 if(ans>dp[i]) 50 ans=dp[i],loc=i; 51 } 52 printf("%d %d ",loc,ans); 53 } 54 return 0; 55 }
2018-08-17