zoukankan      html  css  js  c++  java
  • poj2342 Anniversary party(树形dp入门题)

    http://poj.org/problem?id=2342

    题目给你一个n表示总人数,然后又给了n个人的欢乐度,还有n-1个上下级关系。然后要求在n个人里选一些人,并且选的人里任意两人没有直接上下级的关系,问你最多可以选到的欢乐度是多少?

     题解:先定义状态dp[i][0]表示第i个人不去,子树i的最大欢乐度,dp[i][1]表示第i个人去,子树i的最大值。dp[i][1]先初始化为i节点的欢乐度,dp[i][0]初始化为0,随便选取一个点为根节点建一颗树,用dfs从上往下搜索,直到搜到了叶子节点,假设叶子节点j,因为叶子节点是没有儿子节点的,所以dp[j][0]=0,dp[j][1]=a[j],然后从叶子节点回溯到其父节点,对父节点(假设父节点i)的信息更新用,dp[i][0]+=max(dp[j][0],dp[j][1]),dp[i][1]+=dp[j][0],(这里之所以用+=是因为i节点的儿子节点可能不止一个),,就一直这样从下往上递推,最后max(dp[root][1],dp[root][0])就是要的答案.

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    #define maxn 6005
    vector<int>son[maxn];//相当于邻接表,用来存边关系
    bool vis[maxn];//标记访问过的节点
    int dp[maxn][2];
    void dfs(int root)//搜到叶子节点,然后回溯更新父节点的值
    {
        vis[root]=1;
        for(int i=0;i<son[root].size();i++)
        {
            int v=son[root][i];
            if(!vis[v])
            {
                dfs(v);
                dp[root][1]+=dp[v][0];
                dp[root][0]+=max(dp[v][0],dp[v][1]);
    
            }
        }
    }
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            son[i].clear();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
                scanf("%d",&dp[i][1]);
                dp[i][0]=0;
        }
        int fa,so;
        while(scanf("%d%d",&so,&fa)!=EOF)
        {
            if(so==0&&fa==0) break;
            son[fa].push_back(so);
            son[so].push_back(fa);
        }
        dfs(1);//这里根节点是随便选取的
        cout<<max(dp[1][0],dp[1][1]);
    
    }
    
  • 相关阅读:
    HTTP客户端
    获取IP地址和域名
    SQL语句、PL/SQL块和SQL*Plus命令之间的区别
    oracle中的游标
    oracle表问题
    精简版web浏览器
    oracle的存储过程
    数据库中的视图
    第一次作业
    折半查找
  • 原文地址:https://www.cnblogs.com/eason9906/p/11755089.html
Copyright © 2011-2022 走看看