总述:tarjan缩点可将复杂图变为DAG,后续可配合topo + dp 或者 记忆化搜索(推荐,其实与前面差不多,但更好写),在稠密图中效果更佳,可代替有向基环森林算法
1158. 受欢迎的牛(tarjan板子)
#include <bits/stdc++.h>
using namespace std;
int n,m;
int scc;
int iscc[10001];
int sccsz[10001];
vector <int> e1[10001];
vector <int> e2[10001];
int in1[10001],out1[10001],in2[10001],out2[10001];
int dfn[10001],low[10001];
int timer;
stack <int> STK;
int cnt,ans;
void tarjan(int x)
{
dfn[x] = low[x] = ++timer;
STK.push(x);
for (int i = 0; i < e1[x].size(); i++)
{
if(!dfn[e1[x][i]])//未访问过
{
tarjan(e1[x][i]);
low[x] = min(low[x],low[e1[x][i]]);
}
else
{
low[x] = min(low[x],dfn[e1[x][i]]);
}
}
if(dfn[x] == low[x])
{
scc++;
int tmp;
do{
tmp = STK.top();
STK.pop();
iscc[tmp] = scc;
sccsz[scc]++;
}while(tmp != x);
}
}
int main()
{
cin >> n >> m;
int a,b;
for (int i = 1; i <= m; i++)
{
cin >> a >> b;
e1[a].push_back(b);
in1[b]++,out1[a]++;
}
for (int i = 1; i <= n; i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < e1[i].size(); j++)
{
if(iscc[i] == iscc[e1[i][j]])continue;
in2[iscc[e1[i][j]]]++;
out2[iscc[i]]++;
}
}
for (int i = 1; i <= scc; i++)
{
if(out2[i] == 0)
{
cnt++;
ans = sccsz[i];
}
}
if(cnt > 1)cout << 0;
else cout << ans;
return 0;
}
此处需注意tarjan内部的应加上是否在stack内的判断,这样可以确保u可以到v
1159. 连通数
#include <bits/stdc++.h>
using namespace std;
int n;
char a;
vector <int>e1[2001],e2[2001];
int in1[2001],out1[2001],in2[2001],out2[2001],sz[2001];
int scc,iscc[2001],timer;
int dfn[2001],low[2001];
stack <int> STK;
int pas,vis[2001],ans;
bool inSTK[2001];
bitset<2010> f[2010];
void tarjan(int x)
{
dfn[x] = low[x] = ++timer;
STK.push(x);
inSTK[x] = true;
for (int i = 0; i < e1[x].size(); i++)
{
int u = e1[x][i];
if(!dfn[u])
{
tarjan(u);
low[x] = min(low[x],low[u]);
}
else if(inSTK[u])//一定要加是否在栈中,这保证了u可以到v
{
low[x] = min(low[x],dfn[u]);//只走一次非数边
}
}
if(dfn[x] == low[x])
{
int tmp;
scc++;
//cout << scc << ":";
do{
tmp = STK.top();
//cout << tmp << " ";
STK.pop();
iscc[tmp] = scc;
sz[scc]++;
inSTK[tmp] = false;
}while(tmp != x);
}
}
void F(int x)
{
for (int i = 0; i < e2[x].size(); i++)
{
int u = e2[x][i];
if(!vis[u])
{
vis[u] = 1;
F(u);
}f[x] |= f[u];
}
//cout << x << " ";
f[x][x] = 1;
//cout << x << " " << f[x] << endl;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
for