zoukankan      html  css  js  c++  java
  • 华山论剑(没有上司的舞会)——树形dp

    华山论剑(没有上司的舞会)

    题目描述

    一日,小策如往常一般打开了自己的传奇,刚上线不久,就收到了帮主的私信。原来帮派里要召开一次武功比拼,让他来邀请各帮派人员,因为有些侠客还是萌新,所以需要小策挨个选取战力高的侠客。

    本帮派——华山,实行了师徒制,每位侠客都有自己的师傅,师傅也有自己的师傅,一直到本帮派帮主。

    每位侠客都有自己的战力,因为本次比拼会在全区直播,大家肯定愿意看更加激烈的战斗,所以肯定是战力越高越好。

    但是还有一个要求,当邀请了一位侠客的师傅的时候,便不能再邀请那位侠客了。

    请你帮助小策来计算,邀请哪些侠客可以使武会的战力总和最大,求最大的战力总和。

    注:并不是师傅的战力一定比徒弟高,也有“青出于蓝而胜于蓝”的情况,但是师徒关系是不变的。

    为了便于计算,我们将每位侠客表上编号 \((1...n)\)

    输入格式

    \(1\) 行是一个整数 \(n\) ,表示有 \(n\) 个侠客;\((1\leq n\leq 6000)\)

    \(2\) 行到第 \((n+1)\) 行,每行一个整数,第 \((i+1)\) 行的整数表示第 \(i\) 号侠客的战力值 \(r (-128\leq r\leq 127)\) (这里你们可能会疑惑了,但是玩游戏怎么不会有个坑逼呢,拉低全员战力)

    \((n+2)\) 行到第 \((2n+1)\) 行,每行输入一堆整数 \(x\)\(y\),表示 \(y\)\(x\) 的师傅

    最后一行输入 \(0,0\)

    输出格式

    输出一行一个整数代表最大的战力总和

    样例

    样例输入

    3
    52
    42
    36
    1 3
    3 2
    0 0
    

    样例输出

    94
    

    基本思路

    根据题目判断,由于有徒弟师傅这种关系,可以讲整个帮派看成一整颗树,帮主便是树根,每位侠客的战力值便是每个树节点的权值,现在就可以判断整个题就是对树形 \(dp\) 的考察。
    但是与常规树形 \(dp\) 不同的是,这个题有个限制条件,便是:父节点被选中时,他的子节点便不能被选中了。

    如果说仅仅定义一个一维的 \(dp[i]\) ,无法进行限制条件的判断。

    所以,需要定义一个二维的 \(dp[i][j]\) ,表示的是以 \(i\) 为根节点的子树,\(i\) 去不去时的最大战力值,\(j\) 表示 \(i\) 去不去的状态,\(j=1\) 便是 \(i\) 去,\(j=0\) 便是 \(i\) 不去。

    那么状态转移方程便可以得出:
    师傅来,徒弟不能来。师傅不来,徒弟就能来。所以,决策便是师傅到底来不来,即对 \(dp[i][j]\) 中的 \(j\) 讨论取 \(1\) 还是取 \(0\) 了。

    for(int i=head[now];i;i=e[i].next){
          dp[now][flag]+=dfs(e[i].to,!flag);
    }
    

    剩下的就注意有负的战力值,初始化的时候就需要注意一下。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10000+50;
    struct Edge{
    	int next;
    	int to;
    }e[maxn];
    int dp[maxn][2];
    int a[maxn];
    int in[maxn];
    int head[maxn];
    int cnt=0;
    int n,x,y,root;
    void insert(int u,int v){
    	e[++cnt].next=head[u];
    	head[u]=cnt;
    	e[cnt].to=v;
    	in[v]++;
    }
    int dfs(int now,bool flag){
    	if(!head[now]){
    		if(flag){
    			return a[now];
    		}else{
    			return 0;
    		}
    	}
    	for(int i=head[now];i;i=e[i].next){
    		dp[now][flag]+=dfs(e[i].to,!flag);
    	}
    	return dp[now][flag];
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<=n;i++){
    		dp[i][1]=max(a[i],0);
    	}
    	for(int i=1;i<n;i++){
    		scanf("%d%d",&x,&y);
    		insert(y,x);
    	}
    	scanf("%d%d",&x,&y);
    	for(int i=1;i<=n;i++){
    		if(!in[i]){
    			root=i;
    			break;
    		} 
    	}
    	dfs(root,0);
    	dfs(root,1);
    	cout<<max(dp[root][0],dp[root][1])<<endl;
    	return 0;
    }
    
  • 相关阅读:
    hrbust 1558 小背包(简单01背包)水坑
    hrbust 1174泉水(DFS深度优先搜索)
    HDU 1115
    HDU 4273
    HDU 2912
    POJ 3528
    HDU 1912
    HDU 4741
    HDU 4617
    POJ 1755
  • 原文地址:https://www.cnblogs.com/Rubyonly233/p/12899489.html
Copyright © 2011-2022 走看看