JSOI Salesman 树形Dp

题目链接 https://www.luogu.com.cn/problem/P6082

分析

这题一眼应该就能看出来是树形DP,题目中都多次暗示了,所以先把定义搞出来,最开始我跳了一个坑就是把状态定义成了\(DP[i][j]\),即在\(i\)号节点停留\(j\)次的最大收益,然后想啊想,就没有然后了。。。。。

模拟几个样例发现停留次数有一个很特殊的性质,就是最多只能经过该点的儿子停留次数-1次,不然就回不了家了,但好像对我们这个转移没有什么帮助,回去读一遍题,发现点权可能为负?负的?那第二维状态就没意义了,我要是那个\(Salesman\),肯定先去赚钱多的,不去亏本的,所以这好像直接用一个贪心就可以了,证明也比较好证吧,去一个权大的点肯定比去一个权小的点收获大,不去负权点肯定比去收获大,所以每次从大到小取够停留次数减一或把正儿子取完即可,所以转移方程就是\(DP[u]=\sum_{i=1}^s{DP[i]}\)

下面考虑第二个问题,多组解,因为这是个树,所以只有两种情况有多组解,一是有一个子树的权值为0,这样不管怎么走都可以,另一个是所选的最后一棵子树与一棵未选的子树权值一样,这样我们完全可以选另外一棵子树。关于选子树的话,我用的是堆,这个判断是不是为空啊什么的比较方便,当然用\(sort\)也行,然后就是代码实现啦,其实想明白也挺简单。

#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int N=1e5+10;
struct Edge{
    int to,nxt;
}e[N<<1];
int Head[N],len;
void Ins(int a,int b){
    e[++len].to=b;e[len].nxt=Head[a];Head[a]=len;
}
struct Node{
    int val,idx;
    Node(){val=idx=0;}
    Node(int a,int b){val=a;idx=b;}
    bool operator <(const Node&A)const{
        return val<A.val;
    }
};
int w[N],lim[N],g[N],dp[N];
inline int read(){
    int w=1,x=0;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)w=-1;ch=getchar();
    }
    while(ch<=‘9‘&&ch>=‘0‘){
        x=x*10+ch-‘0‘;
        ch=getchar();
    }
    return x*w;
}
void dfs(int u,int fa){
    priority_queue<Node > q;
    dp[u]=w[u];
    for(int i=Head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);
        q.push(Node(dp[v],g[v]));
    }
    int tot=1,last;
    while(++tot<=lim[u]&&!q.empty()){
        Node now=q.top();q.pop();
        if(now.val<0)break;
        if(now.val==0){g[u]=1;break;}
        dp[u]+=now.val;
        g[u]|=now.idx;
        last=now.val;
    }
    if(!q.empty())if(q.top().val==last)g[u]=1;
}
int main(){
    int n=read();
    lim[1]=N;
    for(int i=2;i<=n;i++)
        w[i]=read();
    for(int i=2;i<=n;i++)
        lim[i]=read();
    for(int i=1;i<n;i++){
        int a=read(),b=read();
        Ins(a,b);Ins(b,a);
    }
    dfs(1,0);
    cout<<dp[1]<<‘\n‘;
    if(g[1])puts("solution is not unique");
    else puts("solution is unique");
    return 0;
}

原文地址:https://www.cnblogs.com/anyixing-fly/p/12633625.html

时间: 2024-10-12 07:17:48

JSOI Salesman 树形Dp的相关文章

bzoj4472: [Jsoi2015]salesman(树形dp)

Description 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有唯一的可能经过其它城镇的路线. 小T 可以准确地估计出在每个城镇停留的净收益.这些净收益可能是负数,即推销商品的利润抵不上花费.由于交通不便,小T经过每个城镇都需要停留,在每个城镇的停留次数与在该地的净收益无关,因为很多费用不是计次收取的,而每个城镇对小T的商品需求也是相对固定的,停留一次后就饱和了.每个城镇为了强化治安,对外地人的最多停留次数有严格的规定.请你帮小T 设计一个收益最大的

[bzoj4472][树形DP] Salesman

题目 原地址 解说 刚看完这道题感觉还是挺乱的,可能那时候脑子不太清醒,一度觉得自己又要重拾Tarjan了.当然最后还是发觉应该用树形DP. (以下dp[u]代表以u为根的包括自己在内的子树的最大利润,bool g[u]表示u及其子树的方案数是否唯一,唯一则为0,否则为1,t[u]代表u的次数,v[u]代表u的价值) 计算最大利润确实挺简单.有点像之前做过的空调教室,但是多了次数限制和负数,但这不难处理.计算u的时候因为每个儿子在走完之后必须返回u来回到根节点,因此我们只能对儿子的dp值进行排序

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次

HDU 1011 Starship Troopers(树形dp+背包)

Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13109    Accepted Submission(s): 3562 Problem Description You, the leader of Starship Troopers, are sent to destroy a base of