题思:题目要我们求某个点:以这个点为根结点的子树中顶点个数的最大值作为这个点的价值,那么找出价值最小的点,并且输出最小值,价值相等输出靠前的点。
搜索有一点技巧。
题解:
状态很简单dp[i] 表示分割后子树最大的节点数,sum[i]表示顺着递归方向根节点i得到的子树中最大的节点数。
第一次记忆搜索下计算出sum[i],第二次dp
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; typedef __int64 lld; #define oo 0x3f3f3f3f #define maxn 20005 #define maxm 205 int dp[maxn]; struct EDGE { int v,next; }E[maxn<<1]; int sum[maxn]; int head[maxn],tol,n; void inst() { memset(head,-1,sizeof head); tol=0; memset(dp,0,sizeof dp); } void add_edge(int u,int v) { E[tol].v=v; E[tol].next=head[u]; head[u]=tol++; } int dfs(int u,int pre) { sum[u]=1; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(v==pre) continue; sum[u]+=dfs(v,u); } return sum[u]; } void tree_dp(int u,int pre) { for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(v!=pre) { dp[u]=max(dp[u],sum[v]); tree_dp(v,u); } else dp[u]=max(dp[u],n-sum[u]); } } int main() { int u,v,ans,pos,f,T; scanf("%d",&T); while(T--) { scanf("%d",&n); inst(); for(int i=1;i<=n-1;i++) { scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs(1,-1); tree_dp(1,-1); ans=oo; for(int i=1;i<=n;i++) if(dp[i]<ans) { ans=dp[i]; pos=i; } printf("%d %d\n",pos,ans); } return 0; }