HDOJ树形DP专题之Tree Cutting
题目大意:给定一棵树,求移除树中哪些结点后,剩下的结点最多的连通支的结点数目不超过原树总结点的一半。
分析:先用dfs将无根树转为有根树,在一棵有根树中,去掉某个结点后,剩余的分支为儿子结点所在的分支和父亲结点所在的分支,取结点数目最多的一支即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }