簡單樹形dp-poj-1655-Balancing Act
阿新 • • 發佈:2019-02-01
題目連結:
題目意思:
給一棵樹,求去掉一個節點,形成的多棵樹中節點數的最大值最小。
解題思路:
簡單樹形dp.
dp[i]表示兒子中節點數最多的分支節點數。
sum[i]表示i為根的子樹節點總數。
第一遍dfs求出dp和sum,第二遍dfs列舉去掉的節點,max(dp[cur],from) //from表示從父親方向過來節點數,向下的時候from+sum[cur]-sum[v].
程式碼:
#include <iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #define INF 0x3f3f3f3f using namespace std; #define Maxn 21000 int dp[Maxn],cnt,n,nuans,node; int sum[Maxn]; struct Edge { int v; struct Edge * next; }edge[Maxn<<1],*head[Maxn<<1]; void add(int a,int b) { ++cnt; edge[cnt].v=b; edge[cnt].next=head[a]; head[a]=&edge[cnt]; } void dfs1(int cur,int fa) { struct Edge * p=head[cur]; dp[cur]=0; sum[cur]=1; while(p) { int v=p->v; if(v!=fa) { dfs1(v,cur); dp[cur]=max(dp[cur],sum[v]);//表示節點數最多的兒子分支 sum[cur]+=sum[v]; //以該點為根的子樹的總的節點數 } p=p->next; } } void dfs2(int cur,int fa,int from) { struct Edge * p=head[cur]; //if(dp[cur]&&from) int tt=max(dp[cur],from); if(tt<nuans) { nuans=tt; node=cur; } else if(tt==nuans&&cur<node) node=cur; while(p) { int v=p->v; if(v!=fa) dfs2(v,cur,from+sum[cur]-sum[v]); //from表示父親方向節點總數 p=p->next; } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(head,NULL,sizeof(head)); cnt=0; for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs1(1,-1); /* for(int i=1;i<=n;i++) printf("i:%d %d %d\n",i,dp[i],sum[i]);*/ nuans=INF; dfs2(1,-1,0); printf("%d %d\n",node,nuans); } return 0; }