【ソース】
2010 ACM-ICPCマルチ大学教育コンテスト(16) -ホストNUDTによって
灘オープン2002
HDU-3594
UVA-10510
Kattis-サボテン
vjudge
上記の質問バンクの質問の一般的な意味は同じですが、質問の説明と入力形式が異なります。コードはHDUの対象となります。
【トピック説明】
1.強く接続されたグラフです。
2.グラフの各エッジは円に属し、1つの円にのみ属します。
このグラフをCACTUSと呼びます。
1.これは強く接続されたグラフです。
2.グラフの各辺は円に属し、1つの円にのみ属します。
この写真をサボテンの写真と呼びます。
上図のような例があります。左はサボテンですが、右はサボテンではありません。右のグラフのエッジ(0、1)は、(0、1、3)と(0、1、2、3)の2つの円に属しているためです。
上の写真に例があります。左側はサボテンの図ですが、右側はそうではありません。右の図のエッジ(0、1)は、(0、1、3)と(0、1、2、3)の2つの円に属しているためです。
【入力フォーマット】
入力は、いくつかのテストケースで構成されています。最初の行には、テストケースの数を表す整数T(1 <= T <= 10)が含まれています。
いずれの場合も、最初の行には、ポイントの数を表す整数n(1 <= n <= 20000)が含まれています。
次の線、各線には2つの数字aとbがあり、一方向のエッジ(a-> b)を表します。各ケースは(0 0)で終わります。
注意:エッジの総数は50000を超えません。
入力にはいくつかのテストケースが含まれています。最初の行には、テストケースの数を表す整数T(1 <= T <= 10)が含まれています。
いずれの場合も、最初の行には、ポイントの数を表す整数n(1 <= n <= 20000)が含まれています。
次の行では、各行に2つの番号aとbがあり、一方向のエッジ(a-> b)を表します。各ケースは(0 0)で終わります。
注:エッジの総数は50000を超えません。
[出力フォーマット]
いずれの場合も、このグラフがサボテンであるかどうかを表す「YES」または「NO」を含む行を出力します。
いずれの場合も、出力行には「はい」または「いいえ」が含まれ、画像がサボテンであるかどうかを示します。
【サンプル入力】
2
4
0 1
1 2
2 0
2 3
3 2
0 0
4
0 1
1 2
2 3
3 0
1 3
0 0
【サンプル出力】
YES
NO
[分析]
問題解決のアイデア:
1.まず、最初にtarjanアルゴリズムのアプリケーションを習得する必要があります。
2.サボテングラフの3つの特性を理解する必要
があります。(1)サボテンdfsグラフに水平エッジを含めることはできません。各ポイントは、強い接続コンポーネントにのみ表示できることを理解してください。
(2)low [v] <dfn [u]、ここでuはvの親ノードです。
(3)a [u] + b [u] <2、a [u]はuノードの息子ノードです。 a [u]低い値がuよりも小さいdfn値。b [u]は、uの逆エッジの数です。
3つのプロパティのいずれかが満たされない場合、それはサボテン図ではありません。
【コード】
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=5e5;
const int inf=1e9;
struct Node {
int to,nt;
} e[N];
int n,m,cnt,tot,num,top,index,flag;
int h[N],fa[N],dfn[N],low[N],instack[N],stap[N],belong[N],vis[N];
inline void add(int x,int y) {
e[cnt].to=y;
e[cnt].nt=h[x];
h[x]=cnt++;
}
void tarjan(int u) {
int v;
dfn[u]=low[u]=++index;
instack[u]=1;
stap[++top]=u;
for(int i=h[u]; i!=-1; i=e[i].nt) {
v=e[i].to;
if(!dfn[v]) {
fa[v]=u;
tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
} else if(instack[v]) {
if(dfn[v]<low[u]) low[u]=dfn[v];
int tmp=u;
while(v!=fa[tmp]) {
vis[tmp]++;
if(vis[tmp]>1) {
flag=1;
return;
}
tmp=fa[tmp];
}
}
}
if(low[u]==dfn[u]) {
tot++;
do {
v=stap[--top];
instack[v]=0;
belong[v]=tot;
} while(v!=u);
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
tot=top=index=flag=0;
memset(h,-1,sizeof(h));
memset(fa,0,sizeof(fa));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(vis,0,sizeof(vis));
int n;
scanf("%d",&n);
while(1) {
int x,y;
scanf("%d%d",&x,&y);
if(x==0 && y==0) break;
add(x+1,y+1);
}
for(int i=1; i<=n; i++) {
if(!dfn[i]) tarjan(i);
}
if(tot>1 || flag) {
puts("NO");
} else puts("YES");
}
return 0;
}