#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
/*
题意; 满足两个条件 1;是一个强连通,2; 每条边仅属于一个环;
*/
const int M = 20005;
const int N = 50005;
struct node {
int to;
int next;
}num[N]; //采用向前星存储图,
int head[N];
int low[M];
int dfn[M];
int ins[M];
int p[M];
int rdu[M];
int cdu[M];
stack<int> s;
int index, cont;
int flag;
int T, n;
void init() {
index = 1;
flag = 1;
cont = 0;
memset(head, -1, sizeof(head));
memset(low, 0, sizeof(low));
memset(ins, 0, sizeof(ins));
memset(dfn, 0, sizeof(dfn));
memset(rdu, 0, sizeof(rdu));
memset(cdu, 0, sizeof(cdu));
memset(p, -1, sizeof(p));
}
void sign(int v, int u) {
while(p[u] != v) {
rdu[u]++;
if(rdu[u] > 1)
{
flag = 0;
break;
}
u = p[u]; //找u的父亲,
}
}
void Tanjian(int u) {
int v;
if(!flag)
return;
dfn[u] = low[u] = index++;
ins[u] = 1;
s.push(u);
for(int k = head[u]; k != -1; k = num[k].next) {
v = num[k].to;
if(!dfn[v]) {
p[v] = u;
Tanjian(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v]) { //表示已入栈 但未出栈,
low[u] = min(low[v], low[u]);
sign(v, u); //标记从根到u的所有点,如果在找根的过程中,有一个点背标记两次,则一定存在一条边属于两个环,
if(!flag)
return;
}
}
if(dfn[u] == low[u]) {
cont++;
if(cont > 1) { //如果存在一个以上的强联通图, 则跳出;
flag = 0;
return ;
}
do {
v = s.top();
s.pop();
ins[v] = 0;
}while(u != v);
}
}
int main()
{
int a, b;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
init();
int e = 0;
while(scanf("%d%d", &a, &b)){
if(a == 0 && b == 0)
break;
num[e].to = b;
num[e].next = head[a];
head[a] = e++;
}
for(int i = 0; i < n; i++) {
if(!dfn[i]) {
Tanjian(i);
}
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
hdu3594
最新推荐文章于 2019-10-20 21:15:44 发布