SGU 134 Centroid 树形DP

来源:互联网 发布:费用优化方案 编辑:程序博客网 时间:2024/06/11 04:07

题目大意:

给你一颗树,定义树的中心为:如果去掉某个结点,那么剩下的若干子树中,结点最多的树的结点个数就是某结点的价值,计算所有的点的价值,那么价值最小的点就是树的中心。中心可以存在好多个。要你求那个最小的价值,中心的个数,并把这些中心点的编号按照升序输出。

解题思路:

用一遍dfs就搞定了,从第一个点开始往下遍历,如果没有访问过就去访问。sum[i]指从第一个点往下遍历的方向上,以i为根的子树的结点数之和并加上自己这个点(如果点k是树的最头上的一个点,那么sum[k]=N),之前看别人的博客看不懂为啥要整这个sum,然后恍然大悟,因为你要算某个点的价值的时候,你要比较这个点的子树,取个最大值,然后再用取出来的这个最大值跟自己这个点上面的结点之和比较,也就是跟N-sum[i]比较(i为正在计算价值的点),比较完得出的结果就是ans[i],所有的ans[i]里的minvalue就是要求的答案。然后再遍历一遍,就ok了。O(n)。

感想:

一道老李在vj上贴的题,一开始不会做,看了别人的博客才会的,唉,自己太水,要多多努力才行。但是ac了依然很开心,我感觉看不懂别人的代码和思路,还是自己的看的顺眼(貌似每个人都是这样),不管怎样,a了就行。


Sample Input

71 22 32 41 55 66 7

Sample Output

3 11


#include <iostream>#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string>#include <string.h>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <stack>using namespace std;typedef long long LL;const int INF=0x7fffffff;const int MAX_N=16009;int N,minvalue=INF;vector<int> e [MAX_N];bool vis[MAX_N];int sum[MAX_N];int ans[MAX_N];int numlist[MAX_N];int dfs(int a){    int num=1;    int M=0;    vis[a]=1;    for(int i=0;i<e[a].size();i++){        if(!vis[e[a][i]]){            num+=dfs(e[a][i]);            M=max(sum[e[a][i]],M);        }    }    sum[a]=num;    ans[a]=max(M,N-num);    minvalue=min(minvalue,ans[a]);    return num;}int main(){    cin>>N;    int a,b;    memset(vis,0,sizeof(vis));    for(int i=1;i<N;i++){        scanf("%d%d",&a,&b);        e[a].push_back(b);        e[b].push_back(a);    }    dfs(1);    int ct=0;//    cout<<minvalue<<endl;    for(int i=1;i<=N;i++){        if(ans[i]==minvalue){            numlist[ct]=i;            ct++;        }    }//    sort(numlist,numlist+ct);    cout<<minvalue<<" "<<ct<<endl;    for(int i=0;i<ct;i++){        if(i==ct-1){            printf("%d\n",numlist[i]);            break;        }        printf("%d ",numlist[i]);    }    return 0;}


0 0
原创粉丝点击