题目传送门

题目大意

某售货员小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. electron内使用vue-slider-component组件报“$attrs is readonly”错误

    解决办法 安装vue-no-ssr插件 https://www.npmjs.com/package/vue-no-ssr npm install vue-no-ssr --save-dev 代码 &l ...

  2. (七)DVWA之SQL Injection--SQLMap测试(Low)

    目录结构 一.测试需求分析 二.SQLMap利用SQL注入漏洞,获取数据库信息 1.判断是否存在注入点 2.获取DBMS中所有的数据库名称 3.获取Web应用当前连接的数据库 4.列出数据库中的所有用 ...

  3. 为.netcore助力--WebApiClient正式发布core版本

    1 前言 WebApiClient已成熟稳定,发布了WebApiClient.JIT和WebApiClient.AOT两个nuget包,累计近10w次下载.我对它的高可扩展性设计相当满意和自豪,但We ...

  4. python自学Day07(自学书籍python编程从入门到实践)

    第8章 函数 函数是带名字的代码块,用于完成具体的工作. 学习定义函数,向函数传递信息. 学习如何编写主要任务是显示信息的函数,还有用于处理数据并返回一个或一组值得函数. 学习如何将函数存储在被称为模 ...

  5. MySQL 8.0权限认证(上)

    MySQL 8.0授权认证   一.系统权限表   user 存放用户账户信息以及全局级别(所有数据库)权限,决定了来自哪些主机的哪些用户可以访问数据库实例,如果有全局权限则意味着对所有数据库都有此权 ...

  6. ReentrantLock原理分析

    一 UML类图 通过类图ReentrantLock是同步锁,同一时间只能有一个线程获取到锁,其他获取该锁的线程会被阻塞而被放入AQS阻塞队列中.ReentrantLock类继承Lock接口:内部抽象类 ...

  7. MATLAB实例:聚类网络连接图

    MATLAB实例:聚类网络连接图 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 本文给出一个简单实例,先生成2维高斯数据,得到数据之后,用模糊C均值( ...

  8. 环境篇:呕心沥血@CDH线上调优

    环境篇:呕心沥血@线上调优 为什么出这篇文章? 近期有很多公司开始引入大数据,由于各方资源有限,并不能合理分配服务器资源,和服务器选型,小叶这里将工作中的总结出来,给新入行的小伙伴带个方向,不敢说一定 ...

  9. LaTeX常用符号(持续更新)

    参考网址:https://qianwenma.cn/2018/05/17/mathjax-yu-fa-can-kao/# 基本运算 1.乘法$x\times y$ x\times y 2.乘法$x^{ ...

  10. SQL常用取整函数

    1.Round(column_name,decimals):用于把数值字段舍入为指定的小数位数 2.Floor(column_name): 向下取整,主要用于获得小于等于数值表达式的最大整数. 3.C ...