模板 - 强连通分量
Posted yinku
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板 - 强连通分量相关的知识,希望对你有一定的参考价值。
Kosaraju算法 O(n+m)
vector<int> s;
void dfs1(int u)
vis[u] = true;
for (int v : g[u])
if (!vis[v])
dfs1(v);
s.push_back(v);
void dfs2(int u)
color[u] = sccCnt;
for (int v : g2[u])
if (!color[v])
dfs2(v);
void Kosaraju()
s.clear();
for (int i = 1; i <= n; ++i)
if (!vis[i])
dfs1(i);
sccCnt = 0;
for (int i = n; i >= 1; --i)
if (!color[s[i]])
++sccCnt;
dfs2(s[i])
https://www.luogu.org/problem/P1262
首先考虑假如一个间谍没办法被揭发不能被贿赂,也就是他不是可行的入口点也没有别人指向他,那么无解。
否则可能要若干个入度为0的点,这些点必须被贿赂,且这些点能到达的点不需要再贿赂。
否则一定存在环,或者多个环交在一起的,而这些环都是同一强连通分量内的,找这个强连通分量里面的最小的那个。
有个问题就是加入强连通分量里的都不能被贿赂就很尴尬了,所以干脆一开始就把强连通分量用编号最小的点来代替?
这个就是在dfs1的时候把额外的信息维护好了,然后在dfs2的时候维护这个强连通分量的最小花费以及假如是INF的话的最小id。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 3005;
const int INF = 0x3f3f3f3f;
int n,w[MAXN], indeg[MAXN];
vector<int> G[MAXN], G2[MAXN];
//从i点出发的连通分量,染色为c1[i]
int c1[MAXN],cntc1;
bool visc1[MAXN];
//i点所在的强连通分量,染色为c2[i]
int c2[MAXN],cntc2;
int minCost[MAXN], minID[MAXN];
int s[MAXN],cnts;
void dfs1(int u,int c)
c1[u]=c;
for (int v : G[u])
if (!c1[v])
dfs1(v,c);
s[++cnts]=v;
void dfs2(int u, int &minid)
c2[u] = cntc2;
minCost[cntc2] = min(minCost[cntc2], w[u]);
minid = min(minid, minID[cntc2]);
for (int v : G2[u])
if (!c2[v])
dfs2(v, minid);
void Kosaraju(ll &sum, int &minid)
minid = INF;
for (int i = 1; i <= n; ++i)
if (!c1[i])
++cntc1;
dfs1(i,cntc1);
for (int i = n; i >= 1; --i)
if (!c2[s[i]])
++cntc2;
minCost[cntc2] = INF;
minID[cntc2] = INF;
dfs2(s[i], minid);
if(minCost[cntc2] == INF)
minid = min(minid, minID[cntc2]);
else
if(!visc1[c1[s[i]]])
visc1[c1[s[i]]]=true;
sum += minCost[cntc2];
int main()
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int p;
scanf("%d%d", &n, &p);
memset(w, INF, sizeof(w[0]) * (n + 1));
for(int i = 1; i <= p; ++i)
int id, c;
scanf("%d%d", &id, &c);
w[id] = c;
int m;
scanf("%d", &m);
for(int i = 1; i <= m; ++i)
int u, v;
scanf("%d%d", &u, &v);
++indeg[v];
G[u].emplace_back(v);
G2[v].emplace_back(u);
ll sum = 0;
for(int i = 1; i <= n; ++i)
if(indeg[i] == 0 && w[i] == INF)
puts("NO");
printf("%d\\n", i);
return 0;
else if(indeg[i] == 0)
//处理了所有入度为0的点,剩下的必定是独立环
++cntc1;
dfs1(i,cntc1);
visc1[cntc1]=true;
sum += w[i];
int minid;
Kosaraju(sum, minid);
if(minid == INF)
puts("YES");
printf("%lld\\n", sum);
else
//某个强连通分量里有不能被贿赂的点
puts("NO");
printf("%d\\n", minid);
return 0;
以上是关于模板 - 强连通分量的主要内容,如果未能解决你的问题,请参考以下文章