题目传送门

题目大意

某售货员小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. 分布式ID总结

    分布式ID 生成的ID使用场景 几乎所有的业务系统,都有生成一个记录标识的需求,例如:message_id, order_id.这个记录标识往往就是数据库中的唯一主键,数据库上会建立聚集索引(clus ...

  2. Mysql(Mariadb)数据库主从

    Mysql主从复制的实现原理图大致如下: MySQL之间数据复制的基础是以二进制日志文件(binary log file)来实现的,一台MySQL数据库一旦启用二进制日志后,其作为master,它数据 ...

  3. kvm的命令简单使用

    virsh命令常用参数总结   参数 参数说明 基础操作 list 查看虚拟机列表,列出域 start 启动虚拟机,开始一个(以前定义的)非活跃的域 shutdown 关闭虚拟机,关闭一个域 dest ...

  4. Html/css 水平布局居中

    如何设置水平居中显示? 一般的方法是设置宽高,然后以margin去控制,比如:DIV居中的经典方法 本章介绍需要宽度自适应时如何水平居中,以及居中失效的几个点 水平自适应居中 比如设置一个列表水平居中 ...

  5. js 不同时间格式介绍以及相互间的转换

    首先必须要提到的是 Date 对象,它用来处理时间和日期. 使用 new Date() 语句可创建 Date 对象,创建出来的时间格式如下(后面提到的标准时间都是指该格式): Wed Jul 17 2 ...

  6. 分享我在前后端分离项目中Gitlab-CI的经验

    长话短说,今天分享我为前后端分离项目搭建Gitlab CI/CD流程的一些额外经验. Before Gitlab-ci是Gitlab提供的CI/CD特性,结合Gitlab简单友好的配置界面,能愉悦的在 ...

  7. Jackson乱码问题

    在配置文件中加入下面的内容 <!-- Json乱码问题配置--> <mvc:annotation-driven> <mvc:message-converters regi ...

  8. 50道Java集合经典面试题(收藏版)

    前言 来了来了,50道Java集合面试题也来啦~ 已经上传github: https://github.com/whx123/JavaHome 1. Arraylist与LinkedList区别 可以 ...

  9. Eureka加了secsecurity后注册失败

    报错信息: com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known ...

  10. 一篇文章搞懂filebeat(ELK)

    本文使用的filebeat是7.7.0的版本本文从如下几个方面说明: filebeat是什么,可以用来干嘛 filebeat的原理是怎样的,怎么构成的 filebeat应该怎么玩 一.filebeat ...