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

 

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