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

    题目描述

    某大学有 (n) 个职员,编号为 (1ldots n)

    他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

    现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 (r_i),但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。

    所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

    输入格式

    输入的第一行是一个整数 (n)

    (2) 到第 ((n + 1)) 行,每行一个整数,第 ((i+1)) 行的整数表示 (i) 号职员的快乐指数 (r_i)

    ((n + 2)) 到第 (2n) 行,每行输入一对整数 (l, k),代表 (k)(l) 的直接上司。

    输出格式

    输出一行一个整数代表最大的快乐指数。

    输入输出样例

    输入 #1

    7
    1
    1
    1
    1
    1
    1
    1
    1 3
    2 3
    6 4
    7 4
    4 5
    3 5
    

    输出 #1

    5
    

    说明/提示

    数据规模与约定
    对于 (100\%) 的数据,保证 (1leq n leq 6 imes 10^3)(-128 leq r_ileq 127)(1 leq l, k leq n),且给出的关系一定是一棵树。

    2020-5-4

    思路

    很显然,这是一个树形dp(我也没学过,老师说的QWQ),那么首先要找状态转移方程,每个节点有两个需要dp的条件,一个是选或者不选,另一个是当前位置,所以开一个二维数组来记录数据。第一维表示状态,第二维记录位置。所以思路就很清晰了,详情见代码。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    int ru[12010],po[12010],ne[12010],f[5][12010];//开数组,ru数组的含义是有多少个父亲节点,po是父节点编号,next就是子节点,二维的f数组则记录最值答案
    int n,a,b,root;//root是根结点
    void dp(int x)
    {
        for(int i=po[x]; i; i=ne[i]) //我明白这里了,这条边当然要从它的起点开始循环,那么循环一次之后就要到它的下一条边
        {
            dp(i);
            f[1][x]=max(max(f[1][x],f[1][x]+f[0][i]),f[0][i]);//其实这里就是分类讨论,讨论有几种情况,这里分别是:1.只选当前的节点。2.选当前节点并且加上不选的子节点的最值。3.赋值不选的那个子节点位置上的最值。可能会有疑问,我这个大的分类就是选这个节点啊,为什么还能不选这个节点,只选子节点。我也有这个疑问。。。。。。。。。。。。。。。。。。
            f[0][x]=max(max(f[0][x],f[0][x]+f[1][i]),max(f[1][i],f[0][i]));//这里多了一种情况:1.自己不选。2.自己不选选子节点。3.只选子节点。4.不选子节点。我也晕了
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&f[1][i]);
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&b,&a);
            ru[b]++;
            ne[b]=po[a];
            po[a]=b;
        }
        for(int i=1; i<=n; i++)
        {
            if(ru[i]==0)//如果一个节点没有父亲节点,那肯定是根结点
            {
                root=i;//记录根结点的位置
                break;
            }
        }
        dp(root);//从根结点开始dp,因为函数里是先递归,再写内容,所以会从最下面的叶子节点开始,那么到最后数据都在根节点里
        printf("%d",max(f[1][root],f[0][root]));//同上
        return 0;
    }
    

    2020-8-12

    先吐槽一句,三个月前的我怎么这么菜,而且这篇题解写的不好,把初学树形dp的我都绕晕了,这个状态转移实在是太复杂了。经过三个月的成长,我现在终于有能力切掉这道题了。

    思路

    其实还是差不多,开一个二维数组f[i][j]来表示以i为根结点的子树的最大开心度,j为0或1,代表根节点选还是不选,这个思路非常巧妙,只要想到就不难了。树形dp一般来说都是递归求解。所以状态转移方程就是如果没选当前根节点,那么选子节点和不选都可以。如果选了,那么只能不选子节点。即f[x][0] += max( f[y][1] , f[y][0] ) , f[x][1] += f[y][0]。(比三个月前的思路香多了,好理解而且代码很好写)

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<cstdlib>
    #include<ctime>
    using namespace std;
    int n,root;
    int a[6005],v[6005],f[6005][3];
    vector<int> son[6005];
    void dp(int x){
    	f[x][0]=0;
    	f[x][1]=a[x];//选或不选的值
    	for(int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		dp(y);//遍历子树并递归
    		f[x][0]+=max(f[y][1],f[y][0]);
    		f[x][1]+=f[y][0];//状态转移方程
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1,l,k;i<=n-1;i++){
    		scanf("%d%d",&l,&k);
    		son[k].push_back(l);
    		v[l]=1;//标记,便于查找根节点
    	}
    	for(int i=1;i<=n;i++){
    		if(v[i]==0){
    			root=i;//要从根节点开始递归,所以要找根节点
    			break;
    		}
    	}
    	dp(root);
    	printf("%d
    ",max(f[root][0],f[root][1]));//选根节点和不选之间选一个最大值输出
    	return 0;
    }
    
  • 相关阅读:
    Selenium简单测试页面加载速度的性能(Page loading performance)
    Selenium Page object Pattern usage
    Selenium如何支持测试Windows application
    UI Automation的两个成熟的框架(QTP 和Selenium)
    分享自己针对Automation做的两个成熟的框架(QTP 和Selenium)
    敏捷开发中的测试金字塔(转)
    Selenium 的基础框架类
    selenium2 run in Jenkins GUI testing not visible or browser not open but run in background浏览器后台运行不可见
    eclipse与SVN 结合(删除SVN中已经上传的问题)
    配置Jenkins的slave节点的详细步骤适合windows等其他平台
  • 原文地址:https://www.cnblogs.com/57xmz/p/13488764.html
Copyright © 2011-2022 走看看