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
Data Constraint
Hint
【數據規模】
1. 對於20%的數據,N≤200
2. 對於40%的數據,N≤5000
3. 對於100%的數據,N≤10^6
對於這道題,我們可用兩種方法來解決這道題
solution1:兩遍dfs求樹上最長鏈
- 我們先記錄下每個點所連接的邊數,每次dfs記錄下當前答案和ans比較,如果比ans大,那麼我們就記錄當前值
- 一遍dfs之後,我們用得出的那個值作爲端點再次進行dfs,然後就可以得出答案
- 考慮細節,第一次dfs之後,記得把數組清空,從端點開始dfs時,答案從1開始累加,之後每次加上它的邊數時要減去1,因爲這個1已經從父親轉移時已經加上
AC代碼
#include<cstdio>
#include<cstring>
#define si 1000010
#define re register int
using namespace std;
struct edge {
int nex,to;
}e[si<<1];
int n,m,ans,cnt,pos,a[si],head[si];
bool v[si];
inline int read() {
int x=0,cf=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') cf=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*cf;
}
inline void add(int x,int y) {
e[++cnt].to=y,e[cnt].nex=head[x],head[x]=cnt;
}
inline void dfs(int x,int t,int op) {
v[x]=true;
for(re i=head[x];i;i=e[i].nex) {
int y=e[i].to;
if(v[y]) continue;
if(op) dfs(y,t+a[y],0);
else dfs(y,t+a[y]-1,0);
}
if(t>ans) ans=t,pos=x;
}
int main() {
n=read(),m=read();
for(re i=1;i<=m;i++) {
int x=read(); a[x]++;
int y=read(); a[y]++;
add(x,y),add(y,x);
}
dfs(1,1,1);
memset(v,0,sizeof(v));
dfs(pos,1,1);
printf("%d",ans);
return 0;
}
solution2:樹形DP
- 對於這道題,考慮本質,其實就是給你一棵樹,求樹上最長鏈及其最長鏈上連接的點
- 定義狀態:設數組f[x]記錄從x開始不含x以及x的父親的最大毛毛蟲
- 對於每一個節點x,我們用數組s來記錄x所有連接的點數(不包含x的父節點)
- 考慮狀態轉移,對於每一個節點,每次都從他的子節點加上自己的所有連接點數
- 注意細節:數組記得要開大,每次取ans時,我們要判斷當前是否是根節點,如果是根節點,那麼我們就不能加1,否則需要再加1
AC代碼
#include<bits/stdc++.h>
#define size 1000010
using namespace std;
struct edge {
int next,to;
}e[size<<1];
int n,m,cnt,ans,val,head[size],f[size],s[size];
void add(int x, int y) {
e[++cnt].to=y,e[cnt].next=head[x],head[x]=cnt;
}
void dfs(int x,int fa) {
for(int i=head[x];i;i=e[i].next) {
int y=e[i].to;
if(y==fa) continue;
s[x]++;
}
for(int i=head[x];i;i=e[i].next) {
int y=e[i].to;
if(y==fa) continue;
dfs(y,x);
if(fa>0) val=1;
else val=0;
ans=max(ans,f[x]+f[y]+1+val);
f[x]=max(f[x],f[y]+s[x]);
}
}
int main() {
cin>>n>>m;
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
cout<<ans;
return 0;
}
如果有洛谷號,還可以做一下這道題 多道紫題