您的位置:首页 > 其它

hdu 1269 迷宫城堡【scc+Tarjan入门】

2017-09-15 17:26 375 查看
Problem Description

为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。

Input

输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。

Output

对于输入的每组数据,如果任意两个房间都是相互连接的,输出”Yes”,否则输出”No”。

Sample Input

3 3

1 2

2 3

3 1

3 3

1 2

2 3

3 2

0 0

Sample Output

Yes

No

推荐:

Tarjan详解1

Tarjan详解2

思路:

Tarjan解强连通分量裸题,照着kuangbin的板子写的;

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
const int maxn = 10010;
using namespace std;
int head[maxn];
int stack[maxn]; //维护一个栈
bool instack[maxn]; //表示i点在栈中
int belong[maxn]; //belong[i] = a, 表示i点属于第a个连通分量
int dfn[maxn]; //为节点u搜索的次序编号(时间戳)
int low[maxn]; //为u或u的子树能够追溯到的最早的栈中节点的次序号
int num[maxn]; //各个强连通分量包含点的个数,数组编号1~scc
int index; //表示到达某个点的时间
int top; //用作栈顶的指针
int scc; //记录连通分量个数
int tot;
bool flag = true;

struct Edge {
int to;
int next;
}edge[maxn << 3];

void add_edge(int u, int v) {
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}

void tarjan(int u) {
if(!flag) return;
int v;
low[u] = dfn[u] = ++index;
stack[top++] = u;
instack[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next) {
v = edge[i].to;
if(!dfn[v]) { //这个if 就是用来更新low[u]
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) { //这里表示找完一个强连通分量
scc++;  //强连通个数加1
if(scc > 1) {
flag = false;
return;
}
do {
v = stack[--top];
instack[v] = false;
belong[v] =  scc;
num[scc]++;
}
while(v != u); //一直到v=u都是属于第scc个强连通分量
}
}

void solve(int n) {
memset(dfn, 0, sizeof(dfn));
memset(instack, false, sizeof(instack));
memset(num, 0, sizeof(num));
index = scc = top = 0;
for(int i = 1; i <= n; i++) { //对所有点tarjan才能求出所有的点的强连通分量
if(!dfn[i] && flag)
tarjan(i);
}
if(flag) printf("Yes\n");
else printf("No\n");
}

int main() {
int n, m, A, B;
while(scanf("%d %d", &n, &m), (n + m)) {
memset(head, -1, sizeof(head));
tot = 0, flag = true;
while(m--) { //邻接表存图
scanf("%d %d", &
4000
amp;A, &B);
add_edge(A, B);
}
solve(n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: