题目
Description
图中有N个点,每两点间只有唯一的路径,对于这样一个给定的图,最大的“毛毛虫”会有多大。毛毛虫包含一条主链,毛毛虫中的节点,要不在主链上,要么和主链上某节点相邻,如下图所示有两只合法的毛毛虫,点数越多,毛毛虫越大。
Input
输入文件第一行两个整数N,M(N≤1000000)
接下来M行,每行两个整数a, b(a, b≤N)
你可以假定没有一对相同的(a, b)会出现一次以上。
Output
一个整数ans,表示最大的毛毛虫的大小。
Sample Input
5 4
1 2
1 3
4 1
5 1
Sample Output
5
Hint
【数据规模】
1. 对于20%的数据,N≤200
2. 对于40%的数据,N≤5000
3. 对于100%的数据,N≤10^6
分析
好像要求树上最长链,但一看样例,就发现又不行,
其实,这题是要求树上最长链,只不过要转变一下。
这里不仅仅是最长链计算进入答案,而且这个点的周围的点的数量。
我们先预处理出每个点周围点的数量 wi ,作为它的权值。
那么,如果把这个点当做主链加入答案,那就给答案增加 wi−1 。
- 现在只用根据权值,找一条树上最长链就可以了。
做法很简单,只需要两次DFS
第一次,以1号节点为根,找到一个价值最大的点,
第二次,以找到一个价值最大的点为根,再找一次最长链。
Code(c++)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <stdlib.h>
#include <math.h>
#define ll long long
#define N 1000007
using namespace std;
struct arr{
int x,y;
}t[5*N];
int next[2*N],a[2*N],b[2*N];
int n,m,tot,f[N],x,ans,w;
bool bz[N];
bool cmp(arr x,arr y)
{
return(x.x<y.x)||((x.x==y.x)&&(x.y<y.y));
}
void dfs(int x,int y)
{
if(y>ans)
{
ans=y;
w=x;
}
for(int i=b[x];i;i=next[i])
if(bz[a[i]])
{
bz[a[i]]=0;
dfs(a[i],y+f[a[i]]-1);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&t[i].x,&t[i].y);
if(t[i].x>t[i].y)
{
int q=t[i].x;
t[i].x=t[i].y;
t[i].y=q;
}
}
sort(t+1,t+1+m,cmp);
for(int i=1;i<=m;i++)
if((t[i].x!=t[i-1].x)||(t[i].y!=t[i-1].y))
{
f[t[i].x]++;
f[t[i].y]++;
tot++;
next[tot]=b[t[i].x];
a[tot]=t[i].y;
b[t[i].x]=tot;
tot++;
next[tot]=b[t[i].y];
a[tot]=t[i].x;
b[t[i].y]=tot;
}
memset(bz,1,sizeof(bz));
ans=0;
bz[1]=0;
dfs(1,f[1]+1);
memset(bz,1,sizeof(bz));
bz[w]=0;
dfs(w,f[w]+1);
printf("%d",ans);
}