题意:给一棵树,对于一个满足以下要求的序列$v_{1\cdots m}$,求最大的$m$
对$\forall1\leq i\lt m$,路径$(v_i,v_{i+1})$不包含$v$中除了$v_i,v_{i+1}$以外的任何点
这个题好神啊...根本做不动
如果一个度数$\geq3$的点$x\in v$,那么它的$\geq3$个子树中只能有至多$2$个子树包含$v$中节点,否则矛盾,所以我们可以找它的一个不包含$v$中节点的子树,并把这个节点移到这个子树中的一个叶子里,移动后$v$仍然满足要求
所以最优解只能包含度数$\leq2$的点
先对叶子讨论,可以证明最优解一定包含叶子:如果一个叶子$x$不在$v$内,那么我们从$x$开始走,如果走到度数$=2$的节点$y$,如果$y\in v$,直接把它移到$x$即可,否则继续往外走;如果走到度数$\geq3$的点$y$,如果它只有一个子树包含$v$中节点,那么继续往那个子树走,否则可以直接把$x$在合适的位置插入$v$中并使得$v$仍然满足要求
最后讨论度数$=2$的点,如果一个度数$=2$的点$x\in v$,把它删掉后树被分成两部分,一部分的点在$v$中的位置在$x$之前,另一部分的点在$v$中的位置在$x$之后,所以所有被选择的度数$=2$的点一定在一条链上
于是DP找出包含最多度数$=2$的点的一条链,这些点的数量加上叶子个数就是答案
#include<stdio.h> #include<algorithm> using namespace std; int h[100010],nex[200010],to[200010],M; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int d[100010],v[100010],f[100010],g[100010]; void dfs(int fa,int x){ f[x]=g[x]=v[x]; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa){ dfs(x,to[i]); f[x]=max(f[x],max(g[x]+g[to[i]],f[to[i]])); g[x]=max(g[x],g[to[i]]+v[x]); } } } int main(){ int n,i,x,y,s; scanf("%d",&n); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); d[x]++; d[y]++; } s=0; for(i=1;i<=n;i++){ s+=d[i]==1; v[i]=d[i]==2; } dfs(0,1); printf("%d",s+f[1]); }