JSOI BZOJ4472 salesman
题目大意
某售货员小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的更多相关文章
- 【树形DP】JSOI BZOJ4472 salesman
题目内容 vjudge链接 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇 之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收 益.这些 ...
- [ JSOI 2015 ] Salesman
\(\\\) \(Description\) 给出一棵以\(1\)为根的\(N\)个节点的树,开始的时候你在\(1\)号节点. 除了\(1\)号节点以外,每个点都有访问次数限制\(t_i\),即到达该 ...
- DP百题练(二)
目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...
- 【题解】 bzoj4472: [Jsoi2015]salesman (动态规划)
bzoj4472,懒得复制,戳我戳我 Solution: 题面意思:从\(1\)号节点出发,每到一个节点就必须停下,获得节点权值(每个节点只会获得一次),每个点有个规定的停留次数,求最大可获得多大权值 ...
- 【BZOJ4472】salesman(树形DP)
题意: 给定一颗有点权的树,每个树上的节点最多能走到lim[u]次,求一条路径,使路径上的点权和最大,每个节点上的点权如果走了多次只能算一次.还要求方案是否唯一. 思路:每个点只能取lim[u]-1个 ...
- bzoj4472:[Jsoi2015]salesman
传送门 树形dp 对于每个点维护其子节点的走法是否唯一,每次取最大的并且不为负的(停留次数-1)个子儿子权值,然后判断走法是否唯一 假如有子节点的权值为0,走法也不唯一 代码: #include< ...
- bzoj4472: [Jsoi2015]salesman(树形dp)
Description 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收益.这些净收益可 ...
- 题解【BZOJ4472】[JSOI2015]salesman
题面 树形\(\text{DP}\)与贪心的结合. 首先考虑树形\(\text{DP}\). 设\(dp_i\)表示从\(i\)出发,访问\(i\)的子树,并且最后回到\(i\)能获得的最大收益. 转 ...
- [bzoj4472][树形DP] Salesman
题目 原地址 解说 刚看完这道题感觉还是挺乱的,可能那时候脑子不太清醒,一度觉得自己又要重拾Tarjan了.当然最后还是发觉应该用树形DP. (以下dp[u]代表以u为根的包括自己在内的子树的最大利润 ...
随机推荐
- Cordova+ionic+angular 项目从 UIWebView 更换为 WKWebView ,通过IOS审核
当前 cordova-ios 最新版本 5.1.1 新版本 cordova-ios 将删除 UIWebView 代码中的所有引用.WKWebView 将是 Cordova 的默认 Web 视图. ...
- tcpdump 基于mac地址抓取数据包
1.刚刚接触tcpdump时,常用tcpdump -i eth1 host 192.168.1.1 这个命令基于ip地址抓取数据包信息. tcpdump -i eth1(接口名称) host 192. ...
- CSS3动画基础
编写页面 记事本或SublimeText或vscode编写html: <html> <div id="box"></div> <style ...
- 在Asp.NET Core中如何优雅的管理用户机密数据
在Asp.NET Core中如何优雅的管理用户机密数据 背景 回顾 在软件开发过程中,使用配置文件来管理某些对应用程序运行中需要使用的参数是常见的作法.在早期VB/VB.NET时代,经常使用.ini文 ...
- netty实现消息中心(二)基于netty搭建一个聊天室
前言 上篇博文(netty实现消息中心(一)思路整理 )大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天. 此demo ...
- php 常用的redis操作语法
String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 $redis-> ...
- 【JAVA进阶架构师指南】之五:JVM性能调优
前言 首先给大家说声对不起,最近属实太忙了,白天上班,晚上加班,回家还要收拾家里,基本每天做完所有事儿都是凌晨一两点了,没有精力再搞其他的了. 好了,进入正题,让我们来聊聊JVM篇最后一个章节 ...
- 资料共享-源代码-视频教程-PLC-OpenCV-C++-MFC
资料共享-源代码-视频教程-PLC-OpenCV-C++-MFC 资料共享-源代码-视频教程 资料共享-源代码-视频教程-PLC-OpenCV-C++-MFC
- 成为python程序员,对疫情过后的毕业生来说,真是一个不错的方向吗?
Python最近几年,一直被炒得很火,这其中有商业因素,但更重要的是即将到来的人工智能时代,而python就恰好是最适合的编程语言. 所以无论是在职的人,还是在校的学生,都想着跟上这一趋势,但,在今年 ...
- 位运算实现加减乘除四则运算(Java)
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 本文是继< ...