zoukankan      html  css  js  c++  java
  • 没有上司的舞会

     

    题目描述

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

    输入格式

    第一行一个整数N。(1<=N<=6000)

    接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)

    接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。

    最后一行输入0 0

    输出格式

    输出最大#include <stdio.h>

    题解:无后效性 树形dp

    dp[i][j]:以i为根节点的子树,j=0表示不选根节点,j=1表示选根节点 的最优解
    dp[i][0] :不选根节点i,可以选择子节点,也可以不选子节点
    dp[i][1] :选根节点i,不可以选子节点
    dp[i][0] = ∑ max(dp[p][1],dp[p,0]);    //可以选子节点也可以不选,取最大的
    dp[i][1] = ∑ dp[p][0] + happy[i];        //选根节点:不选所有子节点 + 根节点的权值
    从根节点开始dfs,自下而上更新,最后取 max(dp[root,0], dp[root,1])  没有作过孩子的结点就是根节点 
    #include <string.h>
    #include <algorithm>
    #define MAX 6005
    
    using namespace std;
    
    int dp[MAX][2];            

    //dp[i][j]:以i为根节点的子树,j=0表示不选根节点,j=1表示选根节点 的最优解 //dp[i][0] :不选根节点i,可以选择子节点,也可以不选子节点 //dp[i][1] :选根节点i,不可以选子节点 //dp[i][0] = ∑max(dp[p][1],dp[p,0]); //可以选子节点也可以不选,取最大的 因为子节点选后,子子节点不可选 //dp[i][1] = ∑dp[p][0] + happy[i]; //选根节点:不选所有子节点 + 根节点的权值 //自下而上 struct Node{ int to; //边的终点 //int w; int next; //相同起点的下一条边的编号(存储位置) }; Node edge[MAX]; int Count; int n,m,k,l; int root; int head[MAX]; //相同起点的最后加入的边的存储位置 int is_root[MAX]; int happy[MAX]; void add_edge(int from, int to){ edge[Count].to=to; //edge[Count].w=w; edge[Count].next = head[from]; head[from] = Count++; } void init(int n ){ Count = 1; //编号初始化为1,因为边1~n //memset(is_root,1,sizeof(is_root)); for(int i =1;i<=n;i++){ edge[i].to=0; edge[i].next=0; head[i]=0; is_root[i]=1; //初始化,假设都为根节点 } } void dfs(int u){ dp[u][0] = 0; //不选自己 dp[u][1] = happy[u]; //选了自己 for(int i=head[u]; i ; i=edge[i].next){     int j = edge[i].to; dfs(j); //dfs孩子,用孩子更新父亲 dp[u][0] += max(dp[j][0], dp[j][1]); //累加儿子选与不选的最大值 dp[u][1] += dp[j][0]; //累加儿子不选 } } int main(){ while(scanf("%d",&n)!=EOF){ init(n); for(int i=1;i<=n;i++) scanf("%d",&happy[i]); for(int i=1;i<=n;i++){ scanf("%d %d",&l,&k); if(l!=0 && k!=0){ add_edge(k,l); //k父亲 l孩子 is_root[l] = 0; //l肯定不是根节点 } } for(int i=1;i<=n;i++){ if(is_root[i] == 1){ root=i; //找到根节点 break; } } dfs(root); //从根节点开始dfs,然后利用子节点更新父节点的信息 printf("%d ",max(dp[root][0],dp[root][1])); //以root为根节点的子树的最优解,输出较大的值 } return 0; }
  • 相关阅读:
    安装HyperV后VirtualBox打开故障
    TortoiseGit或TortoiseSVN在软件或系统更新后图标丢失的一个解决办法
    WSL2 Ubuntu1604 安装 GUI图形库 和 Qt Creator
    时序约束(小梅哥)
    FPGA加速
    吴恩达机器学习笔记
    Neural Network and Deep Learning 笔记【第二章;反向传播算法如何⼯作】
    Tcl学习记录
    Neural Network and Deep Learning 笔记【第一章;手写数字识别】
    操作符重载
  • 原文地址:https://www.cnblogs.com/shiliuxinya/p/12171488.html
Copyright © 2011-2022 走看看