1. 程式人生 > >題解——[HAOI2009]毛毛蟲 樹形DP

題解——[HAOI2009]毛毛蟲 樹形DP

oid father mes 部分 nbsp .com 節點數 因此 ret

題意:

給你一棵樹,從樹中取出一部分滿足:是一條鏈+一些直接連在這條鏈上的節點

求節點數最多的合法取出部分。

技術分享圖片

題解:

其實這題還是不難?

觀察到對於任意一條鏈,

只有兩種情況: 一條路走到底 or 以某個點為中轉

f[x]表示從x往下走,一路走到底的包括x的最優解,

f[x]包括x也包括father[x](將會加入它的貢獻)

觀察到以某個點為中轉的情況:

倘若某條鏈以一個點為中轉,那麽這條鏈將無法向上產生貢獻,

若沒有,則變為第一種情況,且一定可以向上產生貢獻, 以點x為中轉的所有鏈都可以通過各個兒子的搭配得到

因此f[x]可以直接從f[son]中選取最優的來得到,

然後用f[x]來更新ans,

再選取兒子中的前2大,搭配起來加上x組成鏈,更新ans

所以dfs一遍然後輸出ans即可,復雜度O(n);

細節還是挺多的,要註意。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 350000
 5 #define ACway 700000
 6 #define getchar() *o++
 7 char READ[10001000],*o=READ;
 8 int n,m,ans;
 9 int in[AC],f[AC];
10 int date[ACway],Head[AC],Next[ACway],tot;
11 /*觀察到對於任意一條鏈,只有兩種情況: 12 一條路走到底 :以某個點為中轉 13 f[i]表示從i往下走,一條路走到底的最優解(不包括i)(非最長鏈) 14 但這樣並不方便。。。。因為要分的情況太多, 15 所以f[x]表示從x往下走,一路走到底的包括x的最優解, 16 f[x]包括x也包括father[x] 17 觀察到以某個點為中轉的情況: 18 倘若某條鏈以一個點為中轉,那麽這條鏈將無法向上產生貢獻, 19 若沒有,則變為第一種情況。且一定可以向上產生貢獻, 20 以點x為中轉的所有鏈都可以通過各個兒子的搭配得到,*/ 21 22 inline int read() 23 { 24
int x=0;char c=getchar(); 25 while(c > 9 || c < 0) c=getchar(); 26 while(c >= 0 && c <= 9) x=x*10+c-0,c=getchar(); 27 return x; 28 } 29 30 inline void upmax(int &a,int b) 31 { 32 if(b > a) a=b; 33 } 34 35 inline void add(int f,int w) 36 { 37 date[++tot]=w,Next[tot]=Head[f],Head[f]=tot; 38 date[++tot]=f,Next[tot]=Head[w],Head[w]=tot; 39 ++in[f],++in[w]; 40 } 41 42 void pre() 43 { 44 int a,b; 45 n=read(),m=read(); 46 for(R i=1;i<=m;i++) 47 { 48 a=read(),b=read(); 49 add(a,b); 50 } 51 } 52 53 void dfs(int x,int fa) 54 { 55 int now,maxn=0,maxn2=0; 56 f[x]=1 + in[x];//因為包括了自己,所以至少也是1 + in[x]了 57 for(R i=Head[x] ; i ;i=Next[i]) 58 { 59 now=date[i]; 60 if(now == fa) continue; 61 dfs(now,x); 62 upmax(f[x],f[now] + in[x] - 1);//因為既要加自己,又要減兒子,抵消了,所以只用加in就可以了 63 if(f[now] > maxn)//但是由於f[now]會包括x,所以也要減掉,,, 64 { 65 maxn2=maxn; 66 maxn=f[now]; 67 } 68 else upmax(maxn2,f[now]); 69 } 70 upmax(ans,f[x]); 71 upmax(ans,maxn + maxn2 + in[x] - 3);//同上,只不過多減一個兒子 72 }//因為也會包括x,所以會重復2次 73 74 void work() 75 { 76 dfs(1,0);//隨便選個點做根節點吧 77 printf("%d\n",ans); 78 // for(R i=1;i<=n;i++) printf("%d %d\n",i,f[i]); 79 } 80 81 int main() 82 { 83 // freopen("in.in","r",stdin); 84 fread(READ,1,10000000,stdin); 85 pre(); 86 work(); 87 // fclose(stdin); 88 return 0; 89 }

題解——[HAOI2009]毛毛蟲 樹形DP