POJ-2762 Going from u to v or from v to u
Going from u to v or from v to u?
判断是不是弱连通图
\(tarjan\) 缩点 + 拓扑
弱联通说明必须要有唯一的拓扑序,也就是拓扑的队列里始终只有一个
拓扑需要 \(DAG\) 图,因此考虑 \(tarjan\) 缩点后跑拓扑
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1010;
vector<int>gra[maxn], gra_c[maxn];
int low[maxn], dfn[maxn], tp = 0;
int scc[maxn], cnt_scc = 0;
int vis[maxn], du[maxn];
stack<int>st;
void tarjan(int now)
{
vis[now] = 1;
st.push(now);
dfn[now] = low[now] = ++tp;
for(int i=0; i<gra[now].size(); i++)
{
int nex = gra[now][i];
if(dfn[nex] == 0)
{
tarjan(nex);
low[now] = min(low[now], low[nex]);
}
else if(vis[nex])
low[now] = min(low[now], low[nex]);
}
if(low[now] == dfn[now])
{
cnt_scc++;
while(st.top() != now)
{
int x = st.top();
vis[x] = 0;
scc[x] = cnt_scc;
st.pop();
}
vis[now] = 0;
scc[now] = cnt_scc;
st.pop();
}
}
void init(int n)
{
for(int i=0; i<=n; i++) low[i] = dfn[i] = scc[i] = du[i] = 0;
tp = cnt_scc = 0;
for(int i=0; i<=n; i++) {gra[i].clear(); gra_c[i].clear();}
}
bool topu()
{
queue<int>q;
int cnt = 0;
for(int i=1; i<=cnt_scc; i++)
if(du[i] == 0) q.push(i);
while(q.size())
{
if(q.size() != 1) return false;
int now = q.front();
q.pop();
cnt++;
for(int i=0; i<gra_c[now].size(); i++)
{
int nex = gra_c[now][i];
if(--du[nex] == 0)
q.push(nex);
}
}
return cnt == cnt_scc;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n, m;
cin >> n >> m;
init(n);
for(int i=1; i<=m; i++)
{
int a, b;
cin >> a >> b;
gra[a].push_back(b);
}
for(int i=1; i<=n; i++)
if(dfn[i] == 0) tarjan(i);
for(int i=1; i<=n; i++)
{
for(int j=0; j<gra[i].size(); j++)
{
int nex = gra[i][j];
if(scc[i] != scc[nex])
{
gra_c[scc[i]].push_back(scc[nex]);
du[scc[nex]]++;
}
}
}
if(topu()) cout << "Yes\n";
else cout << "No\n";
}
}