ybtoj强连通分块TarjanDP例题1有向图缩点
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ybtoj强连通分块TarjanDP例题1有向图缩点相关的知识,希望对你有一定的参考价值。
Link
解题思路
关于解释Tarjan这件事,这篇博客就是yyds
设
d
i
s
i
dis_i
disi为以i为终点的最大值,
s
i
s_i
si为i点的点权值
设有一条边是
i
−
>
j
i->j
i−>j
d
i
s
j
=
m
a
x
(
d
i
s
j
,
d
i
s
i
+
s
j
)
dis_j = max(dis_j, dis_i+s_j)
disj=max(disj,disi+sj)
优化:Tarjan -》取消了环的无用性
一个强连通分块的值是固定的,先用Tarjan求出来
再用缩出来点进行DP
Code
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
struct DT{
int to, next;
}Ta[500000], a[500000];
int n, m, dye, ans, num, Tnum, now, top, x[10100], y[10100];
int Ts[10100], Thead[10100], low[10100], dfn[10100], hep[10100], co[10100];
int s[10100], head[10100], dis[10100], times[10100];
queue<int>q;
void Tarjan(int x) {
low[x] = dfn[x] = ++now;
hep[++top] = x;
for (int i = Thead[x]; i; i = Ta[i].next) {
if (!dfn[Ta[i].to]) {
Tarjan(Ta[i].to);
low[x] = min(low[x], low[Ta[i].to]);
}
else if (!co[Ta[i].to])
low[x] = min(low[x], dfn[Ta[i].to]);
}
if (low[x] == dfn[x]) {
++dye;
while(hep[top + 1] != x)
co[hep[top--]] = dye;
}
}
void answer() {
for (int i = 1; i <= dye; i++) {
dis[i] = s[i];
if (!times[i]) //用拓扑顺序DP
q.push(i);
}
while(!q.empty()) {
int x = q.front();
q.pop();
for (int i = head[x]; i; i = a[i].next) {
dis[a[i].to] = max(dis[a[i].to], dis[x] + s[a[i].to]); //DP
times[a[i].to]--; //拓扑
if (!times[a[i].to])
q.push(a[i].to);
}
}
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &Ts[i]);
for (int i = 1; i <= m; i++) {
scanf("%d %d", &x[i], &y[i]);
Ta[++Tnum] = (DT){y[i], Thead[x[i]]};
Thead[x[i]] = Tnum;
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
Tarjan(i);
for (int i = 1; i <= n; i++)
s[co[i]] += Ts[i]; //将缩出的点的值更新
for (int i = 1; i <= m; i++)
if (co[x[i]] != co[y[i]]) { //重新对点进行建图
times[co[y[i]]]++;
a[++num] = (DT){co[y[i]], head[co[x[i]]]};
head[co[x[i]]] = num;
}
answer();
for (int i = 1; i <= dye; i++)
ans = max(ans, dis[i]);
printf("%d", ans);
}
以上是关于ybtoj强连通分块TarjanDP例题1有向图缩点的主要内容,如果未能解决你的问题,请参考以下文章