树的最大独立集&没有上司的舞会

树的最大独立集&没有上司的舞会

树的最大独立集题目::

这两道题其实是差不多的,只不过没有上司的舞会多了一个快乐指数,所以这两道题我放到一起来讲。

这两道题都是基础的树形dp题,从题目中我们可以得知,如果一个节点被选了,那么TA的儿子节点就都不能选

由此我们可以设 dp [ i ] [ 0 ] 为不选这个节点的最大取值。

相应的 dp [ i ] [ 1 ] 就为选这个节点的最大取值。

这样我们就可以得到状态转移方程::

 dp [ i ] [ 0 ] = max ( max ( dp [ j ] [ 0 ] ) , max ( dp [ j ] [1 ] ) )

 dp [ i ] [ 1 ] = max ( dp [ j ] [ 0 ] ) + 1(+快乐指数)

如果再直观一点的解释就是::

如果不选这个节点:dp [ i ] [ 0 ] = i节点的所有儿子中选这个儿子或者不选这个儿子的最大值

如果选这个节点:dp [ i ] [ 1 ] = i节点的所有儿子中不选这个儿子的最大值 + i节点本身

好像越说越绕了。。。

所以大家尽量理解一下

注意上面的红字就对了

然后还要注意几点

1、需要递归,从叶子节点开始,最后归到根节点上去,输出 max ( dp [ 根 ] [ 0 ] , dp [ 根 ] [ 1 ] )

2、题目说是无根树,所以需要先转换成有根树,只需要以任意一个点作为根节点即可

然后我们就可以上代码了::

(PS::作者太懒,只想给树的最大独立集的代码)

#include<cstdio>
#include<vector>
using namespace std;
inline void read(int &x) {
    x=0;
    int f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-48;
        s=getchar();
    }
    x*=f;
}
inline void pr(int x) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(x>9)
        pr(x/10);
    putchar(x%10+48);
}//快读快输不解释
vector<int>G[6005];//用vector来存这棵树
int n,k,a,b,dp[6005][2];//按上面说的定义
void dfs(int x,int fa) {//递归搜索
    dp[x][1]=1;//本身
    for(int i=0;i<G[x].size();i++) {//依次找所有的儿子节点中最大的
        int v=G[x][i];
        if(v==fa)//本身
            continue;
        dfs(v,x);//从叶子结点开始更新,这样才能一层层得出答案
        dp[x][1]+=dp[v][0];//儿子节点只能不选
        dp[x][0]+=max(dp[v][0],dp[v][1]);//找最大值更新
    }
}
int main() {
    read(n);
    for(int i=1;i<n;i++)
        read(a),read(b),G[a].push_back(b),G[b].push_back(a);//正常读入
    dfs(1,0);
    pr(max(dp[1][0],dp[1][1]));
}

大概就是这样了,大家有什么不懂的记得在评论区留言哦

觉得好的话就给个关注吧

更多我的博客在这里

猜你喜欢

转载自blog.csdn.net/qq_43890190/article/details/88230458