题目

某售货员小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值得子树的方案不唯一,根节点的方案显然也不唯一.

除此之外,还有存在子树方案唯一但根节点选取子树的方案不唯一的情况.

遍历子树的时候,将 子树方案是否唯一的值 和 根节点选取子树的方案是否唯一 的值进行或运算(只要有一个为真,结果就为真),得到的结果就是这棵树的方案是否唯一,最后输出即可.

那么怎么判断根节点选取子树的方案是否唯一呢,有两种情况:

  1. 相同值引起的不唯一

假设排好序后的子树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)

  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 题解的更多相关文章

  1. bzoj 4472 salesman

    Written with StackEdit. Description 某售货员小\(T\) 要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇 之间都只有唯一的可能经过其它城镇的路线. ...

  2. 【树形dp】 Bzoj 4472 Salesman

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

  3. BZOJ 1179 Atm 题解

    BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来 ...

  4. BZOJ 4472 [Jsoi2015]salesman(树形DP)

    4472: [Jsoi2015]salesman Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 417  Solved: 192[Submit][St ...

  5. bzoj 4472: [Jsoi2015]salesman【树形dp+贪心】

    一个点,设f[u]为要取最大值显然是前最大停留次数-1个儿子的正数f和,排个序贪心即可 判重的话就是看没选的里面是否有和选了的里面f值相同的,有的话就是一.注意在选的时候要把加进f的儿子的g合并上去 ...

  6. 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,记 ...

  7. Bzoj 2064 分裂 题解

    2064: 分裂 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 570  Solved: 350[Submit][Status][Discuss] De ...

  8. Bzoj 2288 生日礼物题解

    2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 856  Solved: 260[Submit][S ...

  9. [CQOI2007]涂色paint(BZOJ 1260)题解

    题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符串表示这个目标:RGBGR. 每次你可以把一段连续的木版涂成一个 ...

随机推荐

  1. AOP面试知识整理,^_^-包括spring Aop

    讲到java企业级开发框架,就不可避免的讲到 IOC,AOP,MCV 今天面试时被问到AOP,讲的很乱,这里整理笔记,包括AOP,spring-AOP的部分知识,错误的地方请小伙伴指出来. 谈谈你对A ...

  2. HTML与CSS 开发常用语义化命名

    一.布局❤️ header 头部/页眉:index 首页/索引:logo 标志:nav/sub_nav 导航/子导航:banner 横幅广告:main/content 主体/内容:container/ ...

  3. 前端每日实战:55# 视频演示如何用纯 CSS 创作一个太阳、地球、月亮的运转模型

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/RJjQYY 可交互视频 此视频是可 ...

  4. python之路-基本数据类型之int整数和bool值

    1.int整数 #整数:主要用来进行数学运算,在python3中所有的整数都是int类型, #整数可以进行的操作有:bit_length(),计算整数在内存中占用的二进制码的长度 #例子:查看整数在内 ...

  5. IDEA Messages Build总是自动弹出提示错误

    IDEA,总是在代码未完成时,在进行切换页面回来后会跳出Messages Build,我相信大家在写java web项目的时候,经常会遇到这个问题,接下来我就和大家说一下问题所在. 主要原因是因为我们 ...

  6. 基于正向扫描的并行区间连接平面扫描算法(IEEE论文)

    作者: Panagiotis Bouros ∗Department of Computer ScienceAarhus University, Denmarkpbour@cs.au.dkNikos M ...

  7. PyCharm设置远程虚拟环境

    1. 创建项目 2. 配置解释器 1. 先打开srttings 2. 选择配置解释器选项 3. 配置远端虚拟环境 4. 成功提示 5. 查看pip列表信息 经过以上操作,PyCharm设置远程虚拟环境 ...

  8. ggplot之多变量绘图

    1. 普通plot 准备数据. x<-seq(0,2*pi,0.05) y<-sin(x) z<-cos(x) data<-data.frame(x,y,z) plot: pl ...

  9. js中字符串 stringObject 的 replace() 方法

    一.定义 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的字符串. 二.语法 stringObject.replace(regexp/substr,repl ...

  10. js 完美运动框架

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...