Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 11911 | Accepted: 5019 |
Description
Input
Output
Sample Input
1 7 2 6 1 2 1 4 4 5 3 7 3 1
Sample Output
1 2
Source
POJ Monthly--2004.05.15 IOI 2003 sample task
最近在做树形DP的题目,但是队长给我挂的树形DP好像有什么不太对啊?!第三题是树分治啊!喂喂是不是跳的有点过分了呀<手动掀桌>。
嘛,题目还是要做的,不过在做树分治之前我需要先把树的重心掌握,于是顺便找了下别人写的题解,在ACdreamer的blog上发现了这道题。
树的重心,嘛,就是说一个类似于一个稳定的中点(几何没学好概念忘记啦OvO)。在树上的定义也差不多,意思是该树的子树中结点数最多的节点数最少,这句话多读几遍应该能理解=w=
要找树的重心,我们需要知道它的所有的直接子树上的节点数目,这一点用Dfs便能轻松实现,然而如果是一棵无根树,那么对每个点进行查找的时候就会产生重叠,导致复杂度升高。所以我们将其看作一棵有根树,然后从根节点开始查找所有的子节点的子树(递归实现),父节点的子树则用总点数减去(该点子节点和+1)来判断。
题目虽然简单,不过对于理解树形DP还是有一定的帮助。
题目地址:http://poj.org/problem?id=1655
题目代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int MAXN=40010; int n; int u[MAXN],v[MAXN],nex[MAXN]; int fir[MAXN]; bool vis[MAXN]; int e_max; void add_edge(int a,int b) { int e=e_max++; u[e]=a; v[e]=b; nex[e]=fir[a]; fir[a]=e; } int dp[MAXN]; int ans,maxans; void Dfs(int now) { vis[now]=1; dp[now]=0; int tmp=0; for(int e=fir[now];~e;e=nex[e]) { int to=v[e]; if(vis[to]) continue; Dfs(to); tmp=max(dp[to]+1,tmp); dp[now]+=dp[to]+1; //printf("now:%d %d\n",now,dp[now]); } tmp=max(n-dp[now]-1,tmp); //printf("now:%d %d\n",now,tmp); if(tmp<maxans) { maxans=tmp; ans=now; } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); e_max=0; memset(dp,0,sizeof dp); memset(fir,-1,sizeof fir); memset(vis,0,sizeof vis); for(int i=0;i<n-1;i++) { int a,b; scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); } ans=1;maxans=n; Dfs(1); printf("%d %d\n",ans,maxans); } return 0; }