C++樹形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[i][1]爲取了i節點作爲樹的最大獨立集。

     設f[i][0]爲沒取i節點作爲樹的最大獨立集的情況。

     而當它沒取時,i的子節點就可以爲所欲爲了,就是\large f[i][0]=\sum_{j=1}^{m}\;max(f[ch[j]][1],f[ch[j]][0]);

     其中ch[j]爲i的子節點。

     但是當它取了,i的子節點就不得不不取了(悲劇),就是\large f[i][0]=\sum_{j=1}^{m}\;f[ch[j]][0];

       但是,題目說這是一個無根樹,我們就不得不將1強制置爲根,還有每一個節點就必須默認它是葉節點。

     它的狀態就是f[i][1]=1;

        當然,如果它們之間的父子關係混亂了,該怎麼辦呢?

      所以,在DFS時我們就把父親節點存起來如果此節點的子節點是父節點就不再往下遍歷了。

代碼實現:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int n,m,f[6005][3],ans;
vector<int>G[6005];
bool v[6005];
void dfs(int x,int fa)
{
    if(x==0)
       return;
    f[x][1]=1;
    for(int i=0;i<G[x].size();i++)
    {
        if(!v[G[x][i]]&&G[x][i]!=fa)
        {
            v[G[x][i]]=1;
            dfs(G[x][i],x);
            f[x][0]+=max(f[G[x][i]][1],f[G[x][i]][0]);
            f[x][1]+=f[G[x][i]][0];
        }
    }
}
int main()
{
    scanf("%d",&n);
    int a,b;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    v[1]=1;
    dfs(1,-1);//初始的根節點的父親是-1.
    printf("%d",max(f[1][1],f[1][0]));
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章