zoukankan      html  css  js  c++  java
  • 洛谷P1352—没有上司的舞会(树形DP)

    树形DP就是在树的基础上做动态规划
    树形DP有两个方向:
    1.叶->根,回溯是从叶子结点往上更新
    2.根->叶,往往是在从叶往根dfs一遍之后(相当于预处理),再重新往下获取最后的答案。

    题意

    某大学有 n 个职员,编号为 1…n。
    他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
    现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 R[i] ,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
    所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

    思路

    这道题是树形DP中的典中典,从叶子往根回溯。
    建树:根据上司和员工的从属关系建立一个有向树
    每个结点有一个价值,父节点和子节点不能同时选。
    每个结点都是选和不选两种选择。
    状态转移数组:

    dp[u][0]为u结点不去,获得的子树的最大价值
    dp[u][1]为u结点去,获得的子树d饿最大价值
    

    可以看出一共有三种情况和对应的状态转移方程
    1.上司去,员工不去dp[u][1] = r[u] + dp[v][0]
    2.上司不去,员工去dp[u][0] = dp[v][1]
    3.上司不去,员工不去dp[u][0] = dp[v][0]
    第二种和第三种情况合并dp[u][0] = max{dp[v][1],dp[u][0]}

    对根节点进行dfs,最终答案为max{dp[root][0],dp[root][1]}

    #include <iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int MAX_N = 6010; //最多结点数
    int tot;    //标记边的序号
    int head[MAX_N],nxt[MAX_N],ver[MAX_N];  //建树要用到的数组
    int r[MAX_N],flag[MAX_N];   //r为价值,flag标记u是否有上司
    int dp[MAX_N][2];
    void addedge(int u,int v){  //根据邻接表建树的过程
        ver[++tot] = v;     //tot条边指向的点为v
        nxt[tot] = head[u]; //nxt保存以u为始点的下一条边的序号
        head[u] = tot;      //head[u]保存以u为始点的边的序号
    }
    
    void dfs(int u){
        dp[u][0] = 0;   //初始化u不去得到的dp
        dp[u][1] = r[u];    //初始化u去得到的dp
        for(int i = head[u]; i;i = nxt[i]){    //搜索u的所有孩子
            int v = ver[i];
            dfs(v);
            dp[u][1] += dp[v][0];
            dp[u][0] += max(dp[v][0],dp[v][1]);
        }
    }
    int main(){
    	int n;
        cin >> n;
    	for(int i = 1;i <= n;i++)
            cin >> r[i];
        int u,v;
        for(int i = 1;i <= n-1;i++){
            cin >> v >> u;
            addedge(u,v);
            flag[v] = 1;    //v有上司
        }
        int root;
        for(int i = 1;i <= n;i++){  //寻找根节点
            if(!flag[i]){
                root = i;
                break;
            }
        }
        dfs(root);  //从根节点开始dfs
        cout << max(dp[root][0],dp[root][1]) << endl;   //根节点也有选和不选两种选择
    	return 0;
    }
    
    
    作者:inss!w!
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 相关阅读:
    利用Oracle创建数据库
    安装Oracle 10g
    安装ArcGIS Engine 9.3
    安装ArcGIS Desktop 9.3
    绘制扇形效果线条小Bug解决
    MFC画线功能总结
    MFC消息映射机制以及画线功能实现
    truncate
    postgresql死锁处理
    python编程中的if __name__ == 'main': 的作用
  • 原文地址:https://www.cnblogs.com/Hfolsvh/p/15010494.html
Copyright © 2011-2022 走看看