题目

某售货员小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. 时间序列数据库(TSDB)初识与选择(InfluxDB、OpenTSDB、Druid、Elasticsearch对比)

    背景 这两年互联网行业掀着一股新风,总是听着各种高大上的新名词.大数据.人工智能.物联网.机器学习.商业智能.智能预警啊等等. 以前的系统,做数据可视化,信息管理,流程控制.现在业务已经不仅仅满足于这 ...

  2. Web最佳实践阅读总结(2)

    代码符合标准 标准的页面会保证正确的渲染 页面容易被搜索引擎搜索,提高搜索排名(SEO) 提高网站的易用性 网页更好维护和扩展(Validator,HTML Validator 属于Firefox插件 ...

  3. fsLayuiPlugin配置说明

    fsLayuiPlugin 是一个基于layui的快速开发插件,支持数据表格增删改查操作,提供通用的组件,通过配置html实现数据请求,减少前端js重复开发的工作. GitHub下载 码云下载 测试环 ...

  4. emmet快速缩写展开的基本写法与心得

    emmet的基本写法: .ct 点是class <div class="ct"></div> #ct 井号是id <div id="ct&q ...

  5. 【原创】(四)Linux进程调度-组调度及带宽控制

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  6. IntelliJ IDEA 2020 全家桶注册码

    WU78YHTY7E-eyJsaWNlbnNlSWQiOiJPUVQzT0oyNVhFIiwibGljZW5zZWVOYW1lIjoi5rC45LmF5r+A5rS7IGlkZWEubWVkZW1pb ...

  7. 【摩天大楼平地起】基础篇 09 简述N种查找算法

    引言 在开始之前首先可以先思考一下假如没有查找算法会是什么情况?所有数据结构都需要全部遍历一遍,每次都一遍又一遍的查,从本质而言查找算法就是为了提高效率. 经过前人一代又一代的努力,目前的查找算法大致 ...

  8. C++ 动态创建链表

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> struct Node { int data; Node* next; }; Nod ...

  9. git 查看commit的提交记录

    相关命令: git log  查看所有提交记录 git show 查看提交详情 示例: git log: git show: 查看指定commit的详情:git show commitId 查看某次c ...

  10. 《前端之路》- TypeScript(二) 函数篇

    目录 一.定义函数方法 二.定义函数传参 三.可选传参 四.默认传参 五.传递剩余参数 六.函数重载 七.箭头函数 八.总结 一.定义函数方法 在 es5 中定时函数的方法有 命名函数和函数表达式(匿 ...