题目传送门

题目大意

某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇
之间都只有唯一的可能经过其它城镇的路线。 小T 可以准确地估计出在每个城镇停留的净收
益。这些净收益可能是负数,即推销商品的利润抵不上花费。由于交通不便,小T经过每个
城镇都需要停留,在每个城镇的停留次数与在该地的净收益无关,因为很多费用不是计次收
取的,而每个城镇对小T的商品需求也是相对固定的,停留一次后就饱和了。每个城镇为了
强化治安,对外地人的最多停留次数有严格的规定。请你帮小T 设计一个收益最大的巡回方
案,即从家乡出发,在经过的每个城镇停留,最后回到家乡的旅行方案。你的程序只需输出
最大收益,以及最优方案是否唯一。方案并不包括路线的细节,方案相同的标准是选择经过
并停留的城镇是否相同。因为取消巡回也是一种方案,因此最大收益不会是负数。小T 在家
乡净收益是零,因为在家乡是本地人,家乡对小 T当然没有停留次数的限制。

输入

输入的第一行是一个正整数n(5<=n<=100000),表示城镇数目。城镇以1到n的数命名。小T 的家乡命
名为1。第二行和第三行都包含以空格隔开的n-1个整数,第二行的第i个数表示在城镇
i+1停留的净收益。第三行的第i个数表示城镇i+1规定的最大停留次数。所有的最大
停留次数都不小于2。接下来的n-1行每行两个1到n的正整数x,y,之间以一个空格
隔开,表示x,y之间有一条不经过其它城镇的双向道路。输入数据保证所有城镇是连通的。

输出

输出有两行,第一行包含一个自然数,表示巡回旅行的最大收益。如果该方案唯一,在
第二行输出“solution is unique”,否则在第二行输出“solution is not unique”。

样例

样例输入

- -   -   

样例输出

solution is unique
//最佳路线包括城镇 1,2, 4, 5, 9。

分析

题目中的任意两个城镇之间都只有唯一的可能经过其它城镇的路线非常重要,这就说明题目中给出的图一定是一棵树

因此,联系最近学过的内容,我们可以用树形DP求解

题目中给出了停留次数的限制,这其实就是给出了你最多能访问多少子树

注意:在一个节点停留n次说明你可以遍历n-1棵子树,因为你还要从子树返回这一个节点,所以在读入时要w--(为了方便,后文的停留次数都是指--之后的)

那么动态转移方程是什么呢?

其实很简单,就是在停留次数限制内选择价值最大的子树,同时如果一个子树的价值为负,那么我们就不能选

比如上面这幅图,如果在父亲节点只能停留1次,则我们要选择价值最大的节点5

如果停留2次,我们要选择价值最大的两个节点5、3

如果停留3次呢,我们是选择5、3、-1吗?显然不是,因为选择-1这个点会拉低价值,所以我们只选5、3两个点就可以

知道了怎么选择节点,我们来看一下什么情况会出现多种选择

1、既然是重复,那么两个节点价值相同的情况一定要考虑一下

我们看上面这幅图

如果在父亲节点只能停留1次,则我们会有两种情况:选左边的5或者右边的5

如果停留2次,我们只有一种情况:两个5

如果停留3次,我们也有两种情况:选上2个5,左边的4和右边的4再任选一个

停留4次呢?又只有一种了

所以,只有当父亲节点剩余的停留次数为1,而且此时最大值有两个及以上儿子节点,那么就会有多种情况

2、子节点的价值为零

这种情况比较特殊,因为无论你选没选到他,价值都是一样,所以会有两种选择

但是前提是价值为0的节点必须前k大的节点之内,因为如果你都遍历不到他,更谈不上决策了

记录子节点的最大值我们用优先队列就可以

代码

把这两种情况搞清之后,我们就可以开始写代码了

代码的细节在注释里

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=2e5+;
struct asd{
int from,to,next;
}b[maxn];
int tot=,head[maxn];
int da[maxn],cx[maxn];
void ad(int aa,int bb){
b[tot].from=aa;
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}//建边
int f[maxn];//记录最大值
int jud;
void dfs(int now,int fa){
priority_queue<int> q;//默认大根堆
for(int i=head[now];i!=-;i=b[i].next){
int u=b[i].to;
if(u==fa) continue;
dfs(u,now);
q.push(f[u]);//遍历,同时将子节点的值pop进去
}
int cnt=,jl=0x3f3f3f3f;
if(q.size()>=){
int xx=q.top();
q.pop();
jl=q.top();
q.push(xx);
}
//cnt记录所选元素的个数,jl记录上一次选的元素
//这道题数据很水,把jl赋值成0x3f3f3f3f都能过
//下面是错误写法
/*
int cnt=0,jl=0x3f3f3f3f;或者jl=0;jl=任何数
没有后面的判断
虽然能过,但是不对
*/
while(!q.empty()){
cnt++;
int xx=q.top();
if(xx== || (cx[now]==cnt && jl==xx)){
jud=;
}//有两种决策的情况
if(xx< || cx[now]+==cnt) break;//超过停留次数
f[now]+=xx;
jl=xx;
q.pop();//一定要pop
}
while(!q.empty()) q.pop();//pop不pop都可以
}
int main(){
memset(head,-,sizeof(head));
int n;
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&da[i]);
}
for(int i=;i<=n;i++){
scanf("%d",&cx[i]);
cx[i]--;//一定要--
}
cx[]=0x3f3f3f3f;//1号节点可以停留无数次
for(int i=;i<=n;i++){
int aa,bb;
scanf("%d%d",&aa,&bb);
ad(aa,bb);
ad(bb,aa);//建边
}
for(int i=;i<=n;i++){
f[i]=da[i];//给每一个节点初始化价值
}
dfs(,);//从根节点开始遍历
if(jud) printf("%d\nsolution is not unique\n",f[]);
//有多种情况也要输出值,不要忘了
else printf("%d\nsolution is unique\n",f[]);
return ;
}

这道题思维量不小,大家一定要认真思考

JSOI BZOJ4472 salesman的更多相关文章

  1. 【树形DP】JSOI BZOJ4472 salesman

    题目内容 vjudge链接 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇 之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收 益.这些 ...

  2. [ JSOI 2015 ] Salesman

    \(\\\) \(Description\) 给出一棵以\(1\)为根的\(N\)个节点的树,开始的时候你在\(1\)号节点. 除了\(1\)号节点以外,每个点都有访问次数限制\(t_i\),即到达该 ...

  3. DP百题练(二)

    目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...

  4. 【题解】 bzoj4472: [Jsoi2015]salesman (动态规划)

    bzoj4472,懒得复制,戳我戳我 Solution: 题面意思:从\(1\)号节点出发,每到一个节点就必须停下,获得节点权值(每个节点只会获得一次),每个点有个规定的停留次数,求最大可获得多大权值 ...

  5. 【BZOJ4472】salesman(树形DP)

    题意: 给定一颗有点权的树,每个树上的节点最多能走到lim[u]次,求一条路径,使路径上的点权和最大,每个节点上的点权如果走了多次只能算一次.还要求方案是否唯一. 思路:每个点只能取lim[u]-1个 ...

  6. bzoj4472:[Jsoi2015]salesman

    传送门 树形dp 对于每个点维护其子节点的走法是否唯一,每次取最大的并且不为负的(停留次数-1)个子儿子权值,然后判断走法是否唯一 假如有子节点的权值为0,走法也不唯一 代码: #include< ...

  7. bzoj4472: [Jsoi2015]salesman(树形dp)

    Description 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收益.这些净收益可 ...

  8. 题解【BZOJ4472】[JSOI2015]salesman

    题面 树形\(\text{DP}\)与贪心的结合. 首先考虑树形\(\text{DP}\). 设\(dp_i\)表示从\(i\)出发,访问\(i\)的子树,并且最后回到\(i\)能获得的最大收益. 转 ...

  9. [bzoj4472][树形DP] Salesman

    题目 原地址 解说 刚看完这道题感觉还是挺乱的,可能那时候脑子不太清醒,一度觉得自己又要重拾Tarjan了.当然最后还是发觉应该用树形DP. (以下dp[u]代表以u为根的包括自己在内的子树的最大利润 ...

随机推荐

  1. 信道估计(channel estimation)图解——从SISO到MIMO原理介绍

    1. 引言 在所有通信中,信号都会通过一个介质(称为信道),并且信号会失真,或者在信号通过信道时会向信号中添加各种噪声.正确解码接收到的信号而没有太多错误的方法是从接收到的信号中消除信道施加的失真和噪 ...

  2. 一篇关于Android M以后权限介绍的不错的文章

    文章地址:http://www.jianshu.com/p/e1ab1a179fbb/

  3. 传递函数-微分方程-差分方程-Matlab阶跃响应曲线

    Transfer function: 1 ------- 5 s + 1 写成微分方程: 5y'(t)+y(t)=u(t) 向前差分: 5y(k+1)+(T-5)y(k)=Tu(k) T:Sample ...

  4. 【loj - 3056】 「HNOI2019」多边形

    目录 description solution accepted code details description 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时 ...

  5. 攻防世界misc新手区前三题

    1.this_is_flag 从题目以及题目的描述来看,不难发现实际上题目中所描述的就是flag 2.Pdf 拿到题目附件是pdf文件,观察题目描述,题目说图下面什么都没有,那么十有八九图下面肯定是f ...

  6. TensorFlow从0到1之TensorFlow csv文件读取数据(14)

    大多数人了解 Pandas 及其在处理大数据文件方面的实用性.TensorFlow 提供了读取这种文件的方法. 前面章节中,介绍了如何在 TensorFlow 中读取文件,本节将重点介绍如何从 CSV ...

  7. css3动画的实例讲解

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. Activity学习笔记1

    Activity概述 简单的理解Activity就是指Android手机或平板的一个屏,类似Window的一个窗口,浏览器的一个页面. Activity的4种状态 Activity的生命周期 创建Ac ...

  9. 【JMeter_13】JMeter逻辑控制器__执行时间控制器<Runtime Controller>

    执行时间控制器<Runtime Controller> 业务逻辑: 根据输入的Runtime的值,对当前节点下的执行时长进行控制,当执行时长超过限定时长后,执行完当前正在执行的取样器后,跳 ...

  10. 恕我直言你可能真的不会java第2篇:Java Stream API?

    一.什么是Java Stream API? Java Stream函数式编程接口最初是在Java 8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合 ...