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 }

 

posted @ 2012-05-02 21:24  BeatLJ  阅读(202)  评论(0编辑  收藏  举报