SGU 134 Centroid 树形DP

题目大意:

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

解题思路:

用一遍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

7
1 2
2 3
2 4
1 5
5 6
6 7

Sample Output

3 1
1


#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值