動態規划----樹型DP----樹的最大獨立集


一、樹型DP的概念

樹型DP即在樹上進行DP。

樹是無環圖,順序可以是從葉子到根節點,也可以從根到葉子節點。

一般樹型DP的特征很明顯,即狀態可以表示為樹中的節點,每個節點的狀態可以由其子節點狀態轉移而來(從葉子到根的順序),或是由其父親節點轉移而來(從根到葉節點的順序),也可是兩者結合。

找出狀態和狀態轉移方程仍然是樹型DP的關鍵。


二、題目描述

樹的最大獨立集

 對於一棵有N個結點的無根樹,選出盡量多的結點,使得任何兩個結點均不相鄰(稱為最大獨立集)。

輸入

 第1行:1個整數N(1 <= N <= 6000),表示樹的結點個數,樹中結點的編號從1..N

接下來N-1行,每行2個整數u,v,表示樹中的一條邊連接結點u和v

輸出

 第1行:1個整數,表示最大獨立集的結點個數

樣例輸入

11
1 2
1 3
3 4
3 5
3 6
4 7
4 8
5 9
5 10
6 11

樣例輸出

7



三、分析

這道題用枚舉是過不了的,因為數據范圍太大了。
所以,我們決定使用樹型DP。
那么,狀態該怎么定義呢?
上面的概念說了,樹上的每一個節點都是一個狀態,那根節點的狀態就可以由它的兒子的狀態轉移過來。
我們就定義一個數組f[6002][2];
f[i][0]表示以i節點為根的子樹中,i不選進最大獨立集時這顆子樹中選進最大獨立集節點個數。
f[i][1]表示以i節點為根的子樹中,i選進最大獨立集時這顆子樹中選進最大獨立集節點個數。
因為選出的節點不相鄰,所以就可以得出狀態轉移方程

f[i][0]=sum(max(f[ch][0]+f[ch][1])); //因為它沒有選進了獨立集,所以要取它所有兒子的最優解
f[i][1]=sum(f[ch][0]);                      //因為它選進了獨立集,所以它的兒子都不能選進獨立集。


狀態轉移方程寫好了,就剩下一些細節的處理。
1、初始化:如果i為葉子節點,則f[i][0]=0,f[i][1]=1。
2、確立樹的結構:
root=1,dfs(root)。
bool vis[6002];
void dfs(int r)
{
    if(r==0) return;
    vis[r]=1;
    for(int i=1;i<=n;i++){
        if(rela[i][0]==r&&vis[rela[i][1]]==0){//如果父子關系相反,則反轉父子關系。
            int t=rela[i][0];
            rela[i][0]=rela[i][1];
            rela[i][1]=t;
        }
    }
    for(int i=1;i<=n;i++)
        if(rela[i][1]==r&&vis[rela[i][0]]==0)
            dfs(rela[i][0]);
}

有了思路,代碼實現就很簡單了,注意要記憶化遞歸。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM