树形DP水题,设f[x][0]是以x为根的子树,内部只有半条链(就是链的两个端点一个在子树里,一个不在子树里)的最大值,f[x][1]是以x为根的子树,内部有一条完整的链(选两个内部的子树作为链的左端点和右端点)的最大值。
于是可以很轻松的得出DP方程:
一开始f[x][0]=f[x][1]=1
然后dfs,深搜x的子树,记录一下x有多少子节点的同时记录子树的最大半链和次大半链(用来在转移的时候凑成x子树内的整个链)。最后注意细节乱搞搞就行了。
本题不考思维但是比较考验考虑细节的能力。
(具体有哪些坑点不知道,因为是1A)
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #include<cstdlib> #define maxn 300010 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int f[maxn][2]; struct Edge{ int next,to; }edge[maxn*3]; int head[maxn],num; inline void add(int from,int to){ edge[++num]=(Edge){head[from],to}; head[from]=num; } void dfs(int x,int fa){ int fir=0,sec=0,son=0; f[x][1]=f[x][0]=1; for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==fa) continue; son++; dfs(to,x); if(fir<f[to][0]){ sec=fir;fir=f[to][0]; } else if(sec<f[to][0]) sec=f[to][0]; } if(son>1) f[x][1]=max(f[x][1],fir+sec+son-1); else f[x][1]=max(f[x][1],fir+1); f[x][0]=max(f[x][0],fir+son); } int main(){ int n=read(),m=read(); for(int i=1;i<=m;++i){ int x=read(),y=read(); add(x,y); add(y,x); } dfs(1,1); int ans=f[1][1]; for(int i=2;i<=n;++i) ans=max(ans,f[i][1]+1); printf("%d ",ans); return 0; }