HDOJ树形DP专题之Tree Cutting

题目大意:给定一棵树,求移除树中哪些结点后,剩下的结点最多的连通支的结点数目不超过原树总结点的一半。

分析:先用dfs将无根树转为有根树,在一棵有根树中,去掉某个结点后,剩余的分支为儿子结点所在的分支和父亲结点所在的分支,取结点数目最多的一支即可。

View Code
 1 #include <stdio.h>

 2 #include <string.h>

 3 #include <vector>

 4 #define N 10000

 5 #define MAX(a,b) ((a)>(b)?(a):(b))

 6 using namespace std;

 7 vector<int> g[N],dep[N];

 8 int p[N],d[N],cnt[N],sum[N],n,dmax;

 9 void dfs(int u,int fa)

10 {

11   int i,v;

12   d[u]=(fa==-1?0:d[fa]+1);

13   dmax=MAX(dmax,d[u]);

14   dep[d[u]].push_back(u);

15   for(i=0;i<g[u].size();i++)

16   {

17     v=g[u][i];

18     if(v!=fa) dfs(v,p[v]=u);

19   }

20 }

21 void dp()

22 {

23   int i,j,v;

24   memset(sum,0,sizeof(sum));

25   memset(cnt,0,sizeof(cnt));

26   for(i=dmax;i>=0;i--)

27   {

28     for(j=0;j<dep[i].size();j++)

29     {

30       v=dep[i][j];

31       sum[v]+=1;

32       cnt[v]=MAX(cnt[v],n-sum[v]);

33       if(i) sum[p[v]]+=sum[v],cnt[p[v]]=MAX(cnt[p[v]],sum[v]);

34     }

35   }

36 }

37 int main()

38 {

39   int i,u,v,f;

40   while(~scanf("%d",&n))

41   {

42     for(i=0;i<n;i++)  g[i].clear(),dep[i].clear();

43     for(i=1;i<n;i++)

44     {

45       scanf("%d%d",&u,&v),u--,v--;

46       g[u].push_back(v);

47       g[v].push_back(u);

48     }

49     p[0]=-1;

50     dmax=0;

51     dfs(0,-1);

52     dp();

53     for(f=i=0;i<n;i++)

54     {

55       if(cnt[i]*2<=n) f=1,printf("%d\n",i+1);

56     }

57     if(!f) puts("NONE");

58   }

59   return 0;

60 }

 

你可能感兴趣的:(tree)