【模板】缩点(Tarjan算法)/洛谷P3387
题目链接
https://www.luogu.com.cn/problem/P3387
题目大意
给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
题目解析
- 强连通
强连通:有向图 \(D(V,E)\) 两点 \(a,b\) 互相可达,称 \(a,b\) 强连通。
强连通分量:有向图 \(D\) 的点集子集 \(\mathrm{v}\) 两两可达,且 \(\mathrm{v}\) 是极大的(增加任意新点即不满足条件),称 \(\mathrm{v}\) 为 \(D\) 的一个强连通分量。
定理:有向图 \(D\) 可唯一划分为若干强连通分量 \(\mathrm{v_1,v_2,...,v_n}\) 。
- 缩点
缩点,即将有向图 \(D\) 划分为若干强连通分量 \(\mathrm{v_1,v_2,...,v_n}\) 。
将每个强连通分量视作一个点,这些点组成点集 \(V'\) ,强连通分量之间的边组成边集 \(E'\) ,得到一张新的有向图 \(D'(V',E')\)。
定理:有向图 \(D'\) 无环 \((DAG)\)。
- \(Tarjan\) 算法
\(Tarjan\) 算法通过一遍 \(DFS\) ,实现缩点的过程。
其原理简单概括为:
对于一个点 \(p\) , \(DFS\) 记录每个点进入搜索的时间戳(搜索顺序) \(\mathrm{dfn}[p]\),以及是否仍在栈中 \(\mathrm{inStack}[p]\)。
\(DFS\) 找不到新的路径即走到了尽头,记录从该点能到达的时间戳最早的点的时间 \(\mathrm{low}[p]=\min{\mathrm{dfn}[p']}\),那么 \(p\) 和 \(p'\) 之间所有在栈中的点都属于同一个强连通分量。
伪代码如下:
Tarjan(u)
{
dfn[u] = low[u] = ++Index
Stack.push(u)
for each (u->v) in E
if (v is not visited)
Tarjan(v)
low[u] = min(low[u], low[v])
else if (v in Stack)
low[u] = min(low[u], dfn[v])
if (dfn[u] == low[u]) //如果节点u是强连通分量的根
++cnt //增加强连通分量个数
repeat
v = Stack.pop
add v into set[cnt] //将v退栈,为该强连通分量中一个顶点
until (u == v)
}
时间复杂度: \(O(n+m)\)
可以通过下面这个例子,形象地体会一下算法流程:





- 原题目解析
将原有向图 \(D\) 缩点简化为新的有向无环图 \(D'\),新的点权为强连通分量中的点权之和,求 \(D'\) 的一条点权最大路径,只需从各顶点出发一遍 \(DFS\) 即可。
简单说明一下参考代码:
dfn[i], inStack[i]意义同上。
e[i]记录从i点出发的边集,g[k]记录第k个强连通分量的点集。
f[i]意义同low[i]。
u[i]记录原图每个点的点权。
w[k]记录第k个强连通分量的联合点权。
ans[i]记录从i点出发的路径最大点权(记忆化搜索)。
mp为某个点i属于哪个强连通分量的索引(mp{f[i] -> k})。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int f[N], dfn[N], inStack[N], w[N], ans[N], u[N];
int n, m, idx=0, cnt=0;
vector <int> e[N], g[N];
map <int, int> mp;
stack <int> stk;
int tarjan(int x)
{
int b, t;
dfn[x] = f[x] = ++idx;
stk.push(x);
inStack[x] = 1;
for (int i=0; i<e[x].size(); i++)
{
b = e[x][i];
if (!dfn[b]) {
tarjan(b);
f[x] = min(f[b], f[x]);
}
else if (inStack[b]) {
f[x] = min(f[b], f[x]);
}
}
if (dfn[x] == f[x]) {
mp.insert(pair<int, int>(f[x], ++cnt));
w[cnt] = 0;
do {
t = stk.top();
stk.pop();
inStack[t] = 0;
g[cnt].push_back(t);
f[t] = f[x];
w[cnt] += u[t];
} while (x != t);
}
}
int find(int x) {return f[x] == x ? dfn[x] : f[x] = find(f[dfn[x]]);}
int dfs(int x)
{
int k = 0;
ans[x] = w[x];
for (int i=0; i<g[x].size(); ++i)
{
for (int j=0; j<e[g[x][i]].size(); ++j)
{
int b = mp[f[e[g[x][i]][j]]];
if (ans[b] == -1) dfs(b);
if (b != x) k = max(k, ans[b]);
}
}
return ans[x] = ans[x] + k;
}
int main()
{
int i, a, b;
scanf("%d%d", &n, &m);
for (i=1; i<=n; ++i) scanf("%d", &u[i]);
for (i=1; i<=m; ++i) {
scanf("%d%d", &a, &b);
if (a == b) m--, i--;
else e[a].push_back(b);
}
for (i=1; i<=n; ++i) if (!dfn[i]) tarjan(i);
int res = 0;
for (i=1; i<=cnt; ++i) ans[i] = -1;
for (i=1; i<=cnt; ++i){
if (ans[i] == -1) dfs(i);
res = max(res, ans[i]);
}
printf("%d\n", res);
return 0;
}
感谢阅读!
【模板】缩点(Tarjan算法)/洛谷P3387的更多相关文章
- tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows
缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...
- 洛谷P3387 【模板】缩点 题解
背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...
- 洛谷 P3387 【模板】缩点 DAGdp学习记
我们以洛谷P3387 [模板]缩点 来学习DAGdp 1.这道题的流程 //伪代码 for i->n if(i未被遍历) tarjan(i) 缩点() DAGdp() 完成 首先tarjan这部 ...
- 缩点Tarjan算法解析+[题解]受欢迎的牛
(注:我在网上找了一些图,希望原博主不要在意,谢谢,(。☉౪ ⊙。)) 首先来了解什么是强连通分量 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向 ...
- 洛谷3388 【模板】割点 tarjan算法
题目描述 给出一个n个点,m条边的无向图,求图的割点. 关于割点 在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点(cut vertex / articul ...
- hdu 2586 How far away?(LCA模板题+离线tarjan算法)
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- 差分约束算法————洛谷P4878 [USACO05DEC] 布局
题目: 不难看出题意主要是给出ml+md个格式为xi-xj<=ak的不等式,xi-xj为i,j俩头牛的距离,要我们求x1-xn的最大值. 经过上下加减我们可以将这几个不等式化成x1-xn< ...
- 【模板】矩阵快速幂 洛谷P2233 [HNOI2002]公交车路线
P2233 [HNOI2002]公交车路线 题目背景 在长沙城新建的环城公路上一共有8个公交站,分别为A.B.C.D.E.F.G.H.公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另 ...
- 洛谷——P3387 【模板】缩点
P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点, ...
随机推荐
- 2021.8.9考试总结[NOIP模拟34]
T1 Merchant 如果$t=0$时不能达到$s$,那么所拿物品的价值一定关于时间单调递增,答案单调.因此可以特判$0$后二分. 用$sort$复杂度被卡,要用$\textit{nth_eleme ...
- 算法:N-gram语法
一.N-gram介绍 n元语法(英语:N-gram)指文本中连续出现的n个语词.n元语法模型是基于(n - 1)阶马尔可夫链的一种概率语言模型,通过n个语词出现的概率来推断语句的结构.这一模型被广泛应 ...
- 第35篇-方法调用指令之invokespecial与invokestatic
这一篇将详细介绍invokespecial和invokestatic字节码指令的汇编实现逻辑 1.invokespecial指令 invokespecial指令的模板定义如下: def(Bytecod ...
- iostat主要性能指标
iostat参数很多,日常运维中主要关注一下字段(根据这些字段的输出内容一般就可以确定服务器是否存在IO性能瓶颈) 1.%iowait:CPU等待输入输出完成时间的百分比.该值较高,表示磁盘存在I/O ...
- vue配置请求拦截器和响应拦截器
首先确保我们已经设置的store.js进行值的存取,这时候我们需要配置请求和响应的拦截器设置 main.js import Vue from 'vue' import App from './App' ...
- 彻底搞懂Spring状态机原理,实现订单与物流解耦
本文节选自<设计模式就该这样学> 1 状态模式的UML类图 状态模式的UML类图如下图所示. 2 使用状态模式实现登录状态自由切换 当我们在社区阅读文章时,如果觉得文章写得很好,我们就会评 ...
- 说透 Docker:基础
既然要学习 K8S,相信各位读者都已经使用过 Docker 了,Docker 的入门是比较容易的,但 Docker 的网络和存储.虚拟化是相当复杂的,Docker 的技术点比较多,在本章中将会深入介绍 ...
- requests_cookie登陆古诗文网。session的使用
通过登录失败,快速找到登录接口 获取hidden隐藏域中的id的value值 # 通过登陆 然后进入到主页面 # 通过找登陆接口我们发现 登陆的时候需要的参数很多 # _VIEWSTATE: /m1O ...
- PowerDotNet平台化软件架构设计与实现系列(04):服务治理平台
系统和系统之间,少不了数据的互联互通.随着微服务的流行,一个系统内的不同应用进行互联互通也是常态. PowerDotNet的服务治理平台发源于早期的个人项目Power.Apix.这个项目借鉴了工作过的 ...
- [loj2245]魔法森林
枚举携带的"A型守护精灵"数$A_{0}$,那么即只能经过$A_{i}\le A_{0}$的边,并最小化1到$n$路径上最大的$B_{i}$ 将所有边按照$A_{i}$从小到大排序 ...