当前位置:网站首页>图论——强连通分量缩点+拓扑排序
图论——强连通分量缩点+拓扑排序
2022-08-01 21:59:00 【ThXe】
Tarjan算法是一种用于查找已知图中的强连通分量的方法
时间复杂度:O(n+m)//n为点数,m为边数
解法一:并查集维护
#include<bits/stdc++.h>
using namespace std;
#define N 100010
struct edge{
int u, v, nxt;
}e[N];
queue <int> q;
int head[N], cnt, n, m, x, y, vis[N], f[N], c[N], s[N], r[N], ans = 1, W[N];
inline void add(int u, int v){
e[++cnt].u = u;//注意要把 u 也给加上,后面需要调用
e[cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int anc(int x){
if(x == f[x]) return x;
return f[x] = anc(f[x]);
}//并查集模板
void dfs(int u){
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
if(!vis[v]){
//如果没搜索
vis[v] = vis[u] + 1;//记录“深度”
dfs(v);//继续搜
}
int fu = anc(u), fv = anc(v);//anc 是并查集函数
if(vis[fv] > 0){
//一定要是搜索中的
if(vis[fu] < vis[fv]) f[fv] = fu;
else f[fu] = fv;//注意这里,深度小的为父亲
}
}
vis[u] = -1;//标记搜索完
return;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) f[i] = i, scanf("%d", W + i);
for(int i = 1; i <= m; ++i){
scanf("%d%d", &x, &y);
add(x, y);
}
for(int i = 1; i <= n; ++i){
if(!vis[i]){
//如果这个点还没搜索就要继续搜
vis[i] = 1;
dfs(i);
}
}
for(int i = 1; i <= n; ++i) c[anc(i)] += W[i];//缩点权值处理
memset(head, 0, sizeof(head));
cnt = 0;//这里要清零哦-v-
for(int i = 1; i <= m; ++i){
x = f[e[i].u], y = f[e[i].v];//由于在上面已经全部遍历过 anc 函数了,这里直接调用即可
if(x != y) add(x, y), r[y]++;//不在一个强连通分量就连边
}
for(int i = 1; i <= n; ++i){
if(i == f[i] && !r[i]) q.push(i), s[i] = c[i];
}//s[i] 是 dp 数组
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
s[v] = max(s[v], s[u] + c[v]);
if(--r[v] == 0) q.push(v);
}
ans = max(ans, s[u]);
}//toposort 模板
printf("%d", ans);
return 0;
}
tarjan 缩点
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 15;
int n, m, idx, tim, top, s;
int p[maxn], head[maxn], Scc_id[maxn], dfn[maxn], low[maxn];
//DFN(u)为节点u搜索被搜索到时的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
//Scc_id为最终节点属于哪个强连通分量,Scc_id[y]=1,则y节点为1号强联通分量中的点
//p最终为Scc总权值
int stac[maxn], vis[maxn];//栈只为了表示此时是否有父子关系
int h[maxn], in[maxn], dist[maxn];
struct EDGE
{
int to; int next; int from;
}edge[maxn * 10], ed[maxn * 10];//原图、新图
void add(int x, int y)
{
edge[++idx].next = head[x];
edge[idx].from = x;
edge[idx].to = y;
head[x] = idx;
}
void tarjan(int x)
{
low[x] = dfn[x] = ++tim;
stac[++top] = x; vis[x] = 1;
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
}
else if (vis[v])
{
low[x] = min(low[x], low[v]);
}
}
if (dfn[x] == low[x])
{
int y;
while (y = stac[top--])
{
Scc_id[y] = x;
vis[y] = 0;
if (x == y) break;
p[x] += p[y];
}
}
}
int topo()
{
queue <int> q;
int tot = 0;
for (int i = 1; i <= n; i++)
if (Scc_id[i] == i && !in[i])
{
q.push(i);//将强联通分量根节点并且入度为0的节点入队
dist[i] = p[i];//dist为dp数组,以下标为i的点的最大权值
}
while (!q.empty())
{
int k = q.front(); q.pop();
for (int i = h[k]; i; i = ed[i].next)
{
int v = ed[i].to;
dist[v] = max(dist[v], dist[k] + p[v]);
in[v]--;
if (in[v] == 0) q.push(v);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, dist[i]);
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &p[i]);
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= m; i++)
{
int x = Scc_id[edge[i].from], y = Scc_id[edge[i].to];
if (x != y)//如果xy不属于一个强联通分量,则需要连边
{
ed[++s].next = h[x];ed[s].to = y;ed[s].from = x;//add(x,y) s为新idx
h[x] = s;in[y]++;
}
}
printf("%d", topo());
return 0;
}
边栏推荐
猜你喜欢
LeetCode952三部曲之二:小幅度优化(137ms -> 122ms,超39% -> 超51%)
Unity Shader 常规光照模型代码整理
Unity Shader general lighting model code finishing
【建议收藏】ヾ(^▽^*)))全网最全输入输出格式符整理
Based on php hotel online reservation management system acquisition (php graduation project)
教你VSCode如何快速对齐代码、格式化代码
shell specification and variables
Getting Started Database Days4
shell规范与变量
游戏元宇宙发展趋势展望分析
随机推荐
365天挑战LeetCode1000题——Day 046 生成每种字符都是奇数个的字符串 + 两数相加 + 有效的括号
0DFS Medium LeetCode6134. Find the closest node to the given two nodes
[Mobile Web] Mobile terminal adaptation
Lecture 3: Several common table field data types in MySQL database
ARFoundation Getting Started Tutorial U2-AR Scene Screenshot Screenshot
User Experience | How to Measure User Experience?
Based on php online examination management system acquisition (php graduation design)
Shell programming conditional statement
Spark cluster construction
Advanced Algebra_Proof_The algebraic multiplicity of any eigenvalue of a matrix is greater than or equal to its geometric multiplicity
【C语言实现】求两个整数的较大值
File operations of WEB penetration
SQL injection of WEB penetration
高等代数_证明_矩阵的任意特征值的代数重数大于等于其几何重数
Scala练习题+答案
The Microsoft campus ambassador to shout you to autumn recruit!
基于php湘西旅游网站管理系统获取(php毕业设计)
基于php酒店在线预定管理系统获取(php毕业设计)
LeetCode952三部曲之一:解题思路和初级解法(137ms,超39%)
论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》