10.4 国庆 环形dp与基环树笔记

1.知识点

环形dp

环形 dp 的概念

• 环形dp与基环树在许多环形结构的问题中,我们可以在环中从某个位置把环断开,把这个环变成线性的,然后进行 dp 等操作。
• 把能通过上述操作解决的环形问题称作 "可拆解的环形问题" 。

环形 dp 的两种策略

• 第一次在任意位置把环断开成链,按照线性问题求解;第二次通过适当的条件和赋值,保证计算出的状态等价于把断开的位置强制相连。
• 把环断成链,然后复制一倍在末尾

基环树

n 个点的树共有 n1 条边,如果再加上一条边,即 n 个点 n 条边,那树中必然会出现一个环。
• 把这种 n 个点 n 条边的联通无向图,即刚好包含一个环的图,称作 "基环树"。
• 如果不保证连通,那么 n 个点 n 条边的无向图也可能是若干棵基环树组成的森林,简称 "基环树森林"。

外向树

n 个点 n 条边,每个点有且仅有 1 条入边的有向图,被称为 "外向树"。
n 个点 n 条边,每个点有且仅有 1 条出边的有向图,被称为 "内向树"。

基环树的直径

• 基环树中最长的简单路径被称为基环树的最长链,其长度被称为基环树的直径。

基环树找环

• 自己一个很神奇的方法:

  1. 预处理出每个点的 father
  2. 从某个点开始,一直往它的 father 走,边走边做 vis 标记,当走到一个已经访问过的节点时,便找到了环。

Code:

int find(int u)//从 u 点开始找环
{
	vis[u] = true;
	node = u;
	while (!vis[fa[node]])
	{
		node = fa[node];
		vis[node] = true;
	}
	return node;
	//node 为环的一点
}

T1

Link

n 个点,m 条边。每次从任意一个点出发,每次可以走向一个没有访问过的点,或者沿着第一次访问这个点时经过的边后退到上一个点。
• 每到达一个点时,把这个点的编号记录下来,这样最后会组成一个长度为 n 的序列,期望这个序列的字典序最小,求出这个序列。
• 对于 60% 的数据,满足 n5000, m=n1
• 对于 40% 的数据,满足 n5000m=n

Solution

• 数据范围提示了做法 /kk。
60pts 就是白送的,容易可以发现一个性质:到达一个点时,一定要遍历完它的子树后才能返回。
• 题目要求字典序最小,于是用 vector 存图,对每个点的子树内进行排序,最后直接 dfs 即可。
• 而对于另外的 40pts,因为 m=n,所以这是一棵基环树。
• 手玩一下基环树的样例可以发现,一定有一条边是无法经过的,我们枚举这条边,然后 dfs 即可。
• ps:加强版无法通过,可能是 vector 常数太大了/bx/bx。

T2

Link

咕咕咕。

T3

Link

n 个人,每个人都有一个价值,并且每个人都有一个自己讨厌的人(保证不为自己),要求你从这 n 个人里选出若干个人,满足:

  1. 每个人与他讨厌的人不能一同选择
  2. 选出这若干个人的价值和最大
    • 求出价值和。
    n106

Solution

• 把每个人都向他讨厌的人连一条边,那便是 n 个点 n 条边的基环树。
• 先找到环,并把它断开,然后我们跑两遍树形 dp,求这两遍 dp 的最大值。
dp 的话就不多讲了,就是没有上司的舞会裸题,甚至直接 copy 都行/bx/bx。

T4

Link

n 种物品,每个物品可以限制另一种物品,需要你从中取出若干个物品,满足:

  1. 每个物品与它限制的物品不能一起被取出
  2. 选出的物品尽量多
    • 求出能选择的最多数量
    n106

Solution

• 与上题类似。dp 时多加了对 y 选边的限制。

T5

Link

• 题意自己看。/bx

Solution

• 一个简单的环形 dp
• 我们定义 dp[i][j][k] 表示当前走到 i,卖萌了 j 次,当前状态是 k,(k=0 表示当前没有卖萌,k=1 表示现在正在卖萌)
• 那么有方程

f[i][j][0]=max(f[i - 1][j][0],f[i - 1][j][1])
f[i][j][1]=max(f[i - 1][j - 1][0], f[i - 1][j - 1][1] + u[i])

• 因为是环形,先跑一遍 dp,然后把 1,n 都固定正在卖萌,然后再跑一遍 dp,取最大值。

T6

Link

N 座仓库,分布在一个 环形 的公路上,编号为 1N,编号为 i 和编号为 j 的仓库之间的距离定义为 dist(i,j)=min(|ij|,N|ij|)
• 编号为 i 仓库的储存量为 ai,在两个仓库间运货的价值为 ai+aj+dist(i,j)
• 求出哪两座仓库之间运送货物需要的代价最大。

Solution

• 由于是环形,所以用断环为链的方法,把这个环断开,然后进行线性 dp
O(N2) 的暴力显然很好做,但是 N106
• 首先推出式子 fi,j=max{(ai+i)+(ajj)}
• 当 i 固定时,(ai+i) 就确定了下来,然后考虑 ajj 的最大值即可。
• 这一步用单调队列优化,于是时间复杂度变成 O(N)

Code:

for (int i = 2; i <= (n << 1); i ++ )
{
	while (q.size() && q.front() < i - m) q.pop_front();
	ans = max(ans, s[q.front()] - q.front() + s[i] + i);
	while (q.size() && s[q.back()] - q.back() < s[i] - i) q.pop_back();
	q.push_back(i);
}
posted @   恋暗  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示