Tarjan缩点
思路
这个算法的实在含义就是把图中所有强连通分量缩成一个点,然后把图变成一个DAG。
所以,自然的,其实就是求强连通分量而已。
模板
//建图
struct graph{
int cnt;
int hd[N],ne[M],to[M],ed[M];
void adde(int a,int b,int c=0){
to[++cnt]=b;
ne[cnt]=hd[a];
hd[a]=cnt;
ed[cnt]=c;
}
}ori,aft;//原图&缩点后图
int n,m;
int u,v;
//缩点
int scnt;
int scc[N],siz[N];
int dcnt;
int dfn[N],low[N];
bool ins[N];
stack<int> stk;
void tarjan(int rt){
dfn[rt]=low[rt]=++dcnt;
stk.push(rt);ins[rt]=true;
for(int e=ori.hd[rt];e;e=ori.ne[e]){
int nxt=ori.to[e];
if(dfn[nxt]==0){
tarjan(nxt);
low[rt]=min(low[rt],low[nxt]);
}
else if(ins[nxt])low[rt]=min(low[rt],dfn[nxt]);
}
if(dfn[rt]==low[rt]){
scnt++;
while(true){
int tp=stk.top();
stk.pop();ins[tp]=false;
scc[tp]=scnt;
siz[scnt]++;
if(stk.top()==rt)break;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
ori.adde(u,v);
}
for(int i=1;i<=n;i++){
if(dfn[i]==0)tarjan(i);
}
//在新图上连边
for(int i=1;i<=n;i++){
for(int e=ori.hd[i];e;e=ori.ne[e]){
int j=ori.to[e];
if(scc[i]!=scc[j]){
aft.adde(scc[i],scc[j]);
}
}
}
return 0;
}
例题
代码
前注:非题解,不做详细讲解。#include<bits/stdc++.h>
using namespace std;
#define fir first
#define sec second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<int,ll> pil;
typedef pair<ll,ll> pll;
typedef pair<int,pii> pip;
typedef vector<int> veci;
typedef priority_queue<int> bghp;
typedef priority_queue<int,vector<int>,greater<int> > lthp;
const int mod=998244353;
const int N=1e4+5,M=1e5+5;
struct graph{
int cnt;
int hd[N],ne[M],to[M],ed[M];
void adde(int a,int b,int c=0){
to[++cnt]=b;
ne[cnt]=hd[a];
hd[a]=cnt;
ed[cnt]=c;
}
}ori,aft;
int n,m;
int u,v;
int a[N];
int scnt;
int scc[N],siz[N];
int dcnt;
int dfn[N],low[N];
bool ins[N];
stack<int> stk;
void tarjan(int rt){
dfn[rt]=low[rt]=++dcnt;
stk.push(rt);ins[rt]=true;
for(int e=ori.hd[rt];e;e=ori.ne[e]){
int nxt=ori.to[e];
if(dfn[nxt]==0){
tarjan(nxt);
low[rt]=min(low[rt],low[nxt]);
}
else if(ins[nxt])low[rt]=min(low[rt],dfn[nxt]);
}
if(dfn[rt]==low[rt]){
scnt++;
while(stk.top()!=rt){
int tp=stk.top();
stk.pop();ins[tp]=false;
scc[tp]=scnt;
siz[scnt]+=a[tp];
}
stk.pop();ins[rt]=false;
scc[rt]=scnt;
siz[scnt]+=a[rt];
}
}
int f[N];
int ans;
int dg[N];
void topo(graph &g){
queue<int> q;
for(int i=1;i<=g.cnt;i++){
dg[g.to[i]]++;
}
for(int i=1;i<=scnt;i++){
f[i]=siz[i];
if(dg[i]==0)q.push(i);
}
while(!q.empty()){
int now=q.front();q.pop();
for(int e=g.hd[now];e;e=g.ne[e]){
int nxt=g.to[e];
f[nxt]=max(f[nxt],f[now]+siz[nxt]);
if(--dg[nxt]==0)q.push(nxt);
}
}
for(int i=1;i<=scnt;i++){
ans=max(ans,f[i]);
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
cin>>u>>v;
ori.adde(u,v);
}
for(int i=1;i<=n;i++){
if(dfn[i]==0)tarjan(i);
}
for(int i=1;i<=n;i++){
for(int e=ori.hd[i];e;e=ori.ne[e]){
int j=ori.to[e];
if(scc[i]!=scc[j]){
aft.adde(scc[i],scc[j]);
}
}
}
topo(aft);
cout<<ans;
return 0;
}