DP动态规划学习笔记——高级篇上

说了要肝的怎么能咕咕咕呢?

不了解DP或者想从基础开始学习DP的请移步上一篇博客:DP动态规划学习笔记

这一篇博客我们将分为上下两篇(这样就不用咕咕咕了...),上篇是较难一些的DP,下篇则是各种DP的优化手段。

——正片开始—— (为啥我最近的博客都喜欢写这个)

背包类树形DP,树形DP里一种很鬼畜的题目。

简单点讲就是:树上的分组背包。不知道分组背包的也请前往上一篇学习。

我们先来看一道板子题:选课

然后我们一起分析一下这道题(最好自己先想一想),由于每门课的先修课只有一门,所以我们很容易想到用树形结构储存这种关系——>只能从父节点到子节点。但是,这一题的数据会形成一个森林。想一想,为什么?

没错,可能不止一门课没有先修课。但是我们只学过树形DP,怎么办呢?简单,我们自己整一棵树出来呗。

但是原来的父子关系又不能变,怎么整呢?我们新建一个“虚拟课程”0出来,作为“没有先修课的课程”的先修课。也就是说我们把森林里的每一棵树都连到一个新的根节点——0节点上,这样我们就得到了一棵树。

这个想法是不是很妙?然后这题就转换成了一个在树上运行的分组背包。

然后我们来设状态。不会?那你别学了。上一篇博客看了没?快去看。

我们上一篇讲过了,树形DP一般以每个节点x作为第一维...

然后呢?(锤),分组背包啊。哦...

于是我们就得到状态了:设f[x,j]表示我们从以x为根的子树中选j门课能获得的最高学分。

很简单是不是?状态都出来了还不知道方程咩?那我们一起来推一推吧。

我们定义几个变量方便描述,设son(x)表示x的子节点集合,siz(x)表示x的子节点个数,如果选修x这门课,那我们就对于任意y∈son(x),可以从以y为根的的子树中选出若干门课(记为ci)来修...在满足Σci=t-1的基础上,我们尽量要修最高的学分。我们有siz(x)组物品,每组物品有j-1个,其中第i组物品的第k个物品的体积为k,价值为f[y,k],背包的总容积为j-1。

我们从每组中选出至多一个物品,即每个子节点最多转移一个状态到x。我们修完x后,还可以选j-1门课,所以我们要在“物品体积”不超过j-1的情况下,使学分(价值)最大。也就是说我们把“上多少y内的课”作为物品。

然后我们进行树形DP,得到答案:

void dp(int x){
    f[x][0]=0;
    for(int i=0;i<son[x].size();i++){
        int y=son[x][i];
        dp(y);
        for(int j=m+1;j>=1;t--)//虚拟节点必选,所以是m+1
            for(int k=0;k<=j-1;k++)//组内的物品,第x组第k个物品(选k门课)的体积为k
                f[x][j]=max(f[x][j],f[x][j-k]+f[y][k]);
    }
}

主函数部分,我们读入每个f[i][1]作为第i门课的价值——>解释:从以i为子树的课中选1门——>价值就是f[i][1]。

接下来我们还是继续讨论树形DP。

我们目前做的树形DP题都是在有根树上进行树形DP的,如果题目给定是一棵无根树呢?

难道我们需要对以每个点为根都做一次树形DP统计答案吗?当然不是,要是这么做还不如暴力呢。

一般对于这种题目,我们用二次扫描(换根法)来解决。

这种DP又被称为换根DP,什么?你想要题?

没有,(爆锤狗头)...拿去 Accumulation Degree

这好像是我第一次给POJ上的题,皮欧勾的题我都没怎么刷过,不过貌似质量挺好的。

但是我永远喜欢洛谷.jpg,emm,你说你看不懂?Chrome自带翻译,不皮了不皮了。

喏。

给你一个树形的水系(废话那么多懒得翻译了)

有一个有n个节点,n-1条河道的树形水系,每个河道有一个最大容水量c[x][y]c[x][y]表示点x到y的最大容水量,源点可以源源不断出水,以源点作为根节点的树的叶子结点可以无限接纳水,而一个节点水的流量等于流过其儿子节点的水的流量之和,儿子节点水的流量不能超过其与父亲连边的最大容水量,询问最大的源点水流量,n2×10^5。

其实简单点说就是求树形结构上的最大流,但是我们不知道源点。为什么不用网络流?嘘,数据太狗了。

于是我们来快乐地DP啊。不给我源点?我每个点都DP一遍

要是这样能过我还写它干嘛。

不过还是先讲讲怎么DP吧。假设我们知道根节点是x。

那么我们来拆问题了。你看这个问题它又大又烦,不如把它拆掉。

考虑用树形DP拆问题。对于每个节点x,我们发现它只能流向自己的子树,于是可以这样设状态,我们用f[x]表示在以x为根的子树中,以x为源点流向子树的最大流量。然后我们对于每个子树都可以拆成小子树,再拆,再拆...就到叶节点了,问题就得解了。

切,刚刚还那么傲娇的大问题现在还不是被脱的一件不剩,看到DP的魅力了吧?再大的问题,只要你是DP题,我就能把你拆掉。

然后我们就很自然的得到了转移方程式:

$$f[x]=\sum\limits_{\text{y∈son(x)}} \begin{cases} min(f[x],c(x,y))& \text{x=0}\\ c(x,y)& \text{x!=0} \end{cases}$$

Latex新手写上面那个公式写了半个小时...

待填坑

猜你喜欢

转载自www.cnblogs.com/light-house/p/11827497.html
今日推荐