BZOJ 4472 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"。
输入样例
9
-3 -4 2 4 -2 3 4 6
4 4 2 2 2 2 2 2
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
输出样例
9
solution is unique
样例解释
最佳路线包括城镇 1,2, 4, 5, 9
题解
任意两个城镇之间都只有唯一的可能经过其它城镇的路线,说明这一定是一棵树
第一问
这道题明显是树形动规,但加了一个限制条件,就是最大停留次数,联想树形动规时的形式,这个最大停留次数其实和能访问的子树个数有关系.
上图表示了一个DFS过程,其中2,3,4,5,6号都是子树,若将这些子树看成一个点,则DFS过程中经过的节点为
[1] 2 [1] 2 [1] 4 [1] 5 [1] 6 [1]
注意其中的根节点1,出现了6次,本题中就是停留了6次,而1号节点有5棵子树,可以发现,若i节点最大停留次数为\(limit[x]\),则DFS中最多能访问\(limit[x]-1\)棵子树
这些子树中对根节点dp的贡献不同,我们当然要选择其中最大的,所以排一下序,选其中前\(limit[x]-1\)棵子树来更新根节点的dp值.
注意,\(limit[x]-1\)也存在大于子树个数的情况,所以实际操作的时候要取\(limit[x]\)和字数个数的最小值作为更新根节点的子树数量,由于净收益可能是负数,所以更新的时候发现是负数立刻停止即可.
所以遍历子树(已排序)时候,条件为
soni < min(limit[root] - 1, sontot) && dp[sonn[soni + 1]] >= 0
其中,soni
为当前循环遍历的子树时的循环变量(注意不时子树根节点编号),root
为根节点编号,sontot
为子树的数量,sonn
数组保存子树的根节点编号,sonn[soni+1]
为这次循环的子树编号(因为soni在循环内自增1)
还有一个条件
家乡对小T当然没有停留次数的限制
也就是整棵树的根节点无限制次数,那么只需要在DFS之前将根节点的limit
值赋值为无限大即可
第二问
显然,根节点方案是否唯一首先要看其子树,如果有任意一棵更新了根节点dp值得子树的方案不唯一,根节点的方案显然也不唯一.
除此之外,还有存在子树方案唯一但根节点选取子树的方案不唯一的情况.
遍历子树的时候,将 子树方案是否唯一的值 和 根节点选取子树的方案是否唯一 的值进行或运算(只要有一个为真,结果就为真),得到的结果就是这棵树的方案是否唯一,最后输出即可.
那么怎么判断根节点选取子树的方案是否唯一呢,有两种情况:
- 相同值引起的不唯一
假设排好序后的子树dp值为10 9 8 7 6 6 5 4 3 2 1
,而你只能选5个(limit值为6),显然你选择的是10 9 8 7 6
,但是仔细观察,你会发现还有一个相同的6,那么我能不能抛弃第一个6选择第二个6呢?当然可以,那么,这就有了两种选择办法([10] [9] [8] [7] [6] 6 5 4 3 2 1
和[10] [9] [8] [7] 6 [6] 5 4 3 2 1
)
- dp值为0引起的不唯一
假设排好序后的子树dp值为10 9 8 7 6 0
,而你只能选5个(limit值为6),你可以选择10 9 8 7 6
,也可以选择10 9 8 7 6 0
,这两种方案更新的值都是一样的.
出现这两种情况时,直接将这棵树方案是否唯一的赋值为真即可
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100000;
struct edge {
int i, next;
} edges[2 * N + 5];
int head[N + 5], tot, n, w[N + 5], limit[N + 5], dp[N + 5], ansn[N + 5],sonn[N + 5];
void add(int u, int v) {
edges[++tot].i = v;
edges[tot].next = head[u];
head[u] = tot;
}
bool cmp(int a, int b) { return dp[a] > dp[b]; }
void dfs(int root, int f) {
dp[root] = w[root];
int sontot = 0, soni = 0;
for (int i = head[root]; i; i = edges[i].next)
if (edges[i].i != f) dfs(edges[i].i, root);
for (int i = head[root]; i; i = edges[i].next)
if (edges[i].i != f) sonn[++sontot] = edges[i].i;
sort(sonn + 1, sonn + 1 + sontot, cmp);
while (soni < min(limit[root] - 1, sontot) && dp[sonn[soni + 1]] >= 0)
dp[root] += dp[sonn[++soni]], ansn[root] |= ansn[sonn[soni]];//按位或
if (soni < sontot && soni > 0 && dp[sonn[soni]] == dp[sonn[soni + 1]] || dp[sonn[soni]] == 0 && soni > 0)//两种情况,注意边界
ansn[root] = 1;
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) scanf("%d", &w[i + 1]);
for (int i = 1; i < n; i++) scanf("%d", &limit[i + 1]);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
limit[1] = n + 1;//在家乡没有停留限制
dfs(1, 0);
printf("%d\n%s", dp[1], ansn[1] ? "solution is not unique" : "solution is unique");
return 0;
}
BZOJ 4472 salesman 题解的更多相关文章
- bzoj 4472 salesman
Written with StackEdit. Description 某售货员小\(T\) 要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇 之间都只有唯一的可能经过其它城镇的路线. ...
- 【树形dp】 Bzoj 4472 Salesman
题目 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇 之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收 益.这些净收益可能是负数,即推 ...
- BZOJ 1179 Atm 题解
BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来 ...
- BZOJ 4472 [Jsoi2015]salesman(树形DP)
4472: [Jsoi2015]salesman Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 417 Solved: 192[Submit][St ...
- bzoj 4472: [Jsoi2015]salesman【树形dp+贪心】
一个点,设f[u]为要取最大值显然是前最大停留次数-1个儿子的正数f和,排个序贪心即可 判重的话就是看没选的里面是否有和选了的里面f值相同的,有的话就是一.注意在选的时候要把加进f的儿子的g合并上去 ...
- BZOJ 4236~4247 题解
BZOJ 4236 JOIOJI f[i][0..2]表示前i个字符中′J′/′O′/′I′的个数 将二元组<f[i][0]−f[i][1],f[i][1]−f[i][2]>扔进map,记 ...
- Bzoj 2064 分裂 题解
2064: 分裂 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 570 Solved: 350[Submit][Status][Discuss] De ...
- Bzoj 2288 生日礼物题解
2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 856 Solved: 260[Submit][S ...
- [CQOI2007]涂色paint(BZOJ 1260)题解
题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符串表示这个目标:RGBGR. 每次你可以把一段连续的木版涂成一个 ...
随机推荐
- 前端每日实战:20# 视频演示如何用纯 CSS 为母亲节创作一颗像素画风格的爱心
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/LmrZVX 可交互视频教程 此视频 ...
- Go coding in go way(用Go的思维去coding)
本文是Tony Bai在2017年第三届GopherChina大会上所作,来源如下 https://tonybai.com/2017/04/20/go-coding-in-go-way/ 一.序 今天 ...
- NSFileHandle的用法(用于读写文件)
利用NSFilehandle类提供的方法,允许更有效地使用文件. 一般而言,处理文件时都要经历以下三个步骤: 1.打开文件,并获取一个NSFileHandle对象,以便在后面的I/O操作中引用该文件 ...
- 如何为SpringBoot服务添加HTTPS证书
HTTPS是HTTP的安全版本,旨在提供数据传输层安全性(TLS).当你的应用不使用HTTP协议的时候,浏览器地址栏就会出现一个不安全的提示.HTTPS加密每个数据包以安全方式进行传输,并保护敏感数据 ...
- 硬核数据结构,让你从B树理解到B+树
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是周五分布式系统的第八篇文章,核心内容是B+树的原理. 今天的文章是上周B树的延伸,所以新关注的或者是有所遗忘的同学建议先从下方链接回顾 ...
- Linux系统系统盘扩容
在Linux学习过程中,可能会遇到根目录存储空间不足的问题,这时候如果只是新增一块硬盘并挂载到某个目录上,还需要将数据转移至新的硬盘中才能缓解存储压力.这种操作未免有些繁琐,那可不可以直接对跟目录进行 ...
- 查看chrome插件源码
简介 想查看chrome插件的源码,就需要找到chrome插件安装的位置,接着再文件夹下查找此插件的id. mac cd ~/Library/Application Support/Google/Ch ...
- SpringCloud之Hystrix服务降级入门全攻略
理论知识 Hystrix是什么? Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟.异常,引起资源耗尽导致系统不可用的解决方案.这说的有点儿太官方了,它的功能主要 ...
- C/C++书籍分享(百度网盘版)
作为第一篇博客,该写一些什么好呢,毕竟作为技术博客开创的,不能随便闲谈不是. 那就分享一些书籍作为见面礼吧.链接里面包含有大量的C++学习用书籍,包含了从入门到进阶的大部分高质量书籍,注意仅用作个人学 ...
- Java-字符流练习。(新手)
参考手册: 关键字: write() 写入存取 close() 结束 flush() 刷新缓冲区(缓冲区就是临时存放数据的区域.) currentTimeMillis() 返回以毫秒为 ...