网址:http://acm.hdu.edu.cn/showproblem.php?pid=1269
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
套着模板把题a了
大概地说明一下算法吧。
算法伪代码如下
tarjan(u)
{
DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
for each (u, v) in E // 枚举每一条边
if (v is not visted) // 如果节点v未被访问过
tarjan(v) // 继续向下找
//low[v]是进行tarjan后的值,必须比较大小
Low[u] = min(Low[u], Low[v])
else if (v in S) // 如果节点u还在栈内 //这里比较大小时因为u可能指向多个顶点,指向完一个小的后可能指向一个大的顶点需要比较
Low[u] = min(Low[u], DFN[v])
if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
repeat
v = S.pop // 将v退栈,为该强连通分量中一个顶点
print v
until (u== v)
}
#include<iostream>
#include<string>
#include<stack>
#include<vector>
using namespace std;
#define mem(arr,a) memset(arr,a,sizeof(arr))
#define N 10000+5
int dfn[N], low[N];
int vis[N];
int counts;
int number;
int top;
int n, m;
vector<int>G[N];
void tarjan(int x){
stack<int>s;
dfn[x] = low[x] = ++counts;
vis[x] = 1;
s.push(x);
for (int i = 0; i < G[x].size(); i++){
int t = G[x][i];
if (!dfn[t]){
tarjan(t);
if (low[t] < low[x])low[x] = low[t];
}
else if (vis[t] && low[x]>dfn[t])low[x] = dfn[t];
}
if (low[x] == dfn[x]){
number++;
while (!s.empty()){
int t = s.top(); s.pop();
vis[t] = 0;
}
}
}
int main(){
while (cin >> n >> m){
if (!n&&!m)break;
mem(vis, 0);
mem(dfn, 0);
mem(low, 0);
number = 0;
counts = 0;
for (int i = 1; i <= m; i++){
int a, b;
cin >> a >> b;
G[a].push_back(b);
}
for (int i = 1; i <= n; i++){
if (!dfn[i])tarjan(i);
}
if (number == 1)cout << "Yes" << endl;
else cout << "No" << endl;
for (int i = 1; i <= n; i++)G[i].clear();
}
}
这个是我原来用邻接阵写的,超内存了,理论上应该是对的,先存在这里吧。
#include<iostream>
#include<string>
#include<stack>
using namespace std;
#define mem(arr,a) memset(arr,a,sizeof(arr))
#define MAX 200+5
#define N 10000+5
int cost[N][N];
int dfn[N], low[N];
int vis[N];
int counts;
int number;
int top;
int n, m;
void tarjan(int x){
stack<int>s;
dfn[x] = low[x] = ++counts;
vis[x] = 1;
s.push(x);
for (int i = 1; i <= n; i++){
if (cost[x][i]){
if (!dfn[i]){
tarjan(i);
if (low[i] < low[x])low[x] = low[i];
}
else {
if (vis[i] && low[x]>dfn[i])low[x] = dfn[i];
}
}
}
if (low[x] == dfn[x]){
number++;
while (!s.empty()){
int t = s.top(); s.pop();
vis[t] = 0;
}
}
}
int main(){
while (cin >> n >> m){
if (!n&&!m)break;
mem(cost, 0);
mem(vis, 0);
mem(dfn, 0);
mem(low, 0);
top = -1;
number = 0;
counts = 0;
for (int i = 1; i <= m; i++){
int a, b;
cin >> a >> b;
cost[a][b] = 1;
}
for (int i = 1; i <= n; i++)if (!dfn[i])
tarjan(i);
if (number == 1)cout << "Yes" << endl;
else cout << "No" << endl;
}
}
加一种写法
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define mem(arr,a) memset(arr,a,sizeof(arr))
#define N 10010
struct node{
int v, next;
};
node edge[N * 10];
int dfn[N], low[N];
int vis[N];
int heads[N];
int cnt, top, counts;
int num;
int stack[N];
int n, m;
void add(int a, int b){
edge[counts].next = heads[a];
edge[counts].v = b;
heads[a] = counts;
counts++;
}
void tarjan(int u){
dfn[u] = low[u] = ++cnt;
vis[u] = 1;
stack[top++] = u;
for (int i = heads[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if (!dfn[v]){
tarjan(v);
if (low[u] > low[v])low[u] = low[v];
}
else if (vis[v] && low[u] > dfn[v])low[u] = dfn[v];
}
if (low[u] == dfn[u]){
num++;
int t;
do{
t = stack[--top];
if (t>0)
vis[t] = 0;
} while (t != u&&top >= 0);
}
}
int main(){
while (cin >> n >> m){
if (!n&&!m)break;
num = cnt = top = counts = 0;
mem(heads, -1);
mem(dfn, 0);
mem(vis, 0);
for (int i = 1; i <= m; i++){
int a, b;
cin >> a >> b;
add(a, b);
}
for (int i = 1; i <= n; i++){
if (!dfn[i])tarjan(i);
}
if (num == 1)cout << "Yes" << endl;
else cout << "No" << endl;
}
}