jzoj 1752. 無聊的草稿 樹形DP | 兩遍dfs

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;
}

如果有洛谷號,還可以做一下這道題 多道紫題

發佈了75 篇原創文章 · 獲贊 86 · 訪問量 3209
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章