- 传送门 -
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1451
| Root |
|
(题面见PDF)
- 代码 -
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4 + 5;
bool INSTK[N];
int STK[N], DFN[N], LOW[N];
int TO[N], HD[N], NXT[N];
int CNT[N], F[N];
int T;
int sz, tp, tot, scc_num;
int n, m, ans;
void init() {
ans = 1;
sz = tp = tot = scc_num = 0;
memset(CNT, 0, sizeof (CNT));
memset(F, 0, sizeof (F));
memset(DFN, 0, sizeof (DFN));
memset(HD, 0, sizeof (HD));
memset(INSTK, false, sizeof (INSTK));
}
void add(int x, int y) {
TO[++sz] = y; NXT[sz] = HD[x]; HD[x] = sz;
}
bool find(int s, int f) {
while (s != f) {
CNT[s] ++;
if (CNT[s] > 1) return false;
s = F[s];
}// 打标记, 祖先节点不打, 因为如果出现别的环和它共用一个节点的情况那共用节点一定是其中一个环的祖先节点
return true;
}
bool tarjan(int x) {
int v;
LOW[x] = DFN[x] = ++tot;
INSTK[x] = true; STK[++tp] = x;
for (int i = HD[x]; i; i = NXT[i]) {
v = TO[i];
if (!DFN[v]) {
F[v] = x;
if (!tarjan(v)) return false;
LOW[x] = min(LOW[x], LOW[v]);
}
else if (INSTK[v]) {
if (!find(x, v)) return false; //判断是否重边
LOW[x] = min(LOW[x], DFN[v]);
}
}
if (LOW[x] == DFN[x]) {
scc_num++;
if (scc_num > 1) return false; //判断强连通分量的数量
do {
v = STK[tp--];
INSTK[v] = false;
}while (v != x);
}
return true;
}
int main() {
scanf("%d", &T);
for (int i = 1; i <= T; ++i) {
init();
scanf("%d%d", &n, &m);
for (int j = 1, x, y; j <= m; ++j) {
scanf("%d%d", &x, &y);
add(x, y);
}
for (int j = 0; j < n; ++j)
if (!DFN[j] && !tarjan(j)) { ans = 0; break; }
if (ans) printf("YES
");
else printf("NO
");
}
}