[HAOI2009]毛毛蟲(樹形dp)
阿新 • • 發佈:2018-09-07
cpp class dfs 代碼 ans 文本文 col 輸入 math 復制
end.
[HAOI2009]毛毛蟲
題目描述
對於一棵樹,我們可以將某條鏈和與該鏈相連的邊抽出來,看上去就象成一個毛毛蟲,點數越多,毛毛蟲就越大。例如下圖左邊的樹(圖 1 )抽出一部分就變成了右邊的一個毛毛蟲了(圖 2 )。
輸入輸出格式
輸入格式:
在文本文件 worm.in 中第一行兩個整數 N , M ,分別表示樹中結點個數和樹的邊數。
接下來 M 行,每行兩個整數 a, b 表示點 a 和點 b 有邊連接( a, b ≤ N )。你可以假定沒有一對相同的 (a, b) 會出現一次以上。
輸出格式:
在文本文件 worm.out 中寫入一個整數 , 表示最大的毛毛蟲的大小。
輸入輸出樣例
輸入樣例#1:
13 12
1 2
1 5
1 6
3 2
4 2
5 7
5 8
7 9
7 10
7 11
8 12
8 13
輸出樣例#1: 復制
11
說明
40% 的數據, N ≤ 50000
100% 的數據, N ≤ 300000
題解
我真傻,真的。
我一開始以為以1為根節點。
然後找兩條分鏈加加起來就好了。
測一下60分,以為是對的。
於是。。。。6點到10點,沒有調出來,生無可戀。
最後還是看題解了。我真菜
我怎麽就沒想到要把每一個點作為一次根呢
然後因為是相連的點換根。所以子樹的變化就是原根少一個點的子樹,那個點的子樹加上原根。
dp判斷一下當前f[i]表示以i為根的最大長度。
然後毛毛蟲可以是拼起來的。也就是說要記錄最長和次長鏈。
代碼
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int N=300005; struct node{ int nex,to; }e[N<<1]; int size[N],n,m,num,head[N]; int f[N],ans,pre[N]; void add(int from,int to){ num++; e[num].to=to; e[num].nex=head[from]; head[from]=num; } int read(){ int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } void dfs(int x,int fa){ size[x]=1;//int sum=0; for(int i=head[x];i;i=e[i].nex){ int v=e[i].to; if(v==fa)continue; size[x]++;dfs(v,x); } } void dfs2(int x,int fa){ int max1=0,max2=0; for(int i=head[x];i;i=e[i].nex){ int v=e[i].to; if(v==fa)continue; dfs2(v,x); if(f[v]>max1){ max2=max1;max1=f[v]; } else if(f[v]>max2)max2=f[v]; f[x]=max(f[x],f[v]+size[x]-1); } ans=max(ans,max1+max2-1+size[x]); } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); add(x,y);add(y,x); size[x]++;size[y]++; } for(int i=1;i<=n;i++)f[i]=1; dfs2(1,0); printf("%d\n",ans); return 0; }
[HAOI2009]毛毛蟲(樹形dp)