第三部分 图论算法 (第四章 强连通分量)例题

本文通过四个例题详细介绍了强连通分量在有向图算法中的应用,包括有向图缩点、寻找受欢迎的节点、求解最大半连通子图和解决恒星亮度问题。通过Tarjan算法进行缩点,将复杂问题简化为无环图,进而使用DP求解最大路径和亮度问题。
摘要由CSDN通过智能技术生成

例题一: 有向图缩点 link

在这里插入图片描述
在这里插入图片描述

思路:
大家一开始可能都会想到直接用SPFA跑最长路,时间复杂度为 O ( n m ) O(nm) O(nm)
看看数据,TLE是必然的。
那有没有时间更优的方法——强连通分量。

分析题意,每个点点权只被计算一次,允许一条边走多次,
那我们考虑用Tarjan来进行缩点,
使图变成有向无环图,再进行 D P DP DP
设转移方程为: f = m a x ( f u + d i s v , f v ) f=max(f_u+dis_v,f_v) f=max(fu+disv,fv)
f i f_i fi表示以i作为终点的路径所经过的最大点权和。

#include<queue>
#include<cstdio>
#include<stack>

using namespace std;

const int N = 1e5 + 10;
struct node {
   int to, nxt;} e[N], e_[N];
int n, m, a[N], head[N], KK, tot;
int x, y, dfn[N], low[N], num, in[N], ans;
int sum[N], head_[N], KK_, du[N], dis[N];
queue <int> q;
stack <int> s;

void add(int x, int y) {
   e[++KK] = (node){
   y, head[x]}; head[x] = KK;}

void add_(int x, int y) {
   e_[++KK_] = (node){
   y, head_[x]}; head_[x] = KK_;}

void Tarjan(int now) 
{
   
	dfn[now] = low[now] = ++num;
	s.push(now);
	for (int i = head[now]; i; i = e[i].nxt)
		if (!dfn[e[i].to]) Tarjan(e[i].to), low[now] = min(low[now], low[e[i].to]);
		else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
	
	if (dfn[now] == low[now])
	{
   
		in[now] = ++tot;
		sum[tot] = a[now];
		int tmp = s.top();
		while (tmp != now) s.pop(),in[tmp] = tot,sum[tot] += a[tmp], tmp = s.top();
		s.pop();
	}
}

int main() {
   
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for (int i = 1; i <= m; i++) scanf("%d %d", &x, &y), add(x, y);
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) Tarjan(i);
	
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值