荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: kaman (Aspire追月|Fight for Final), 信区: ACMICPC
标 题: 典型算法与ACM题目解析(02)—有向图的强连通分量zz
发信站: 荔园晨风BBS站 (Wed Nov 8 15:34:42 2006), 站内
发信人: Sempr (偶尔郁闷||进了WorldFinals2007就去pie MM), 信区: Algorithm
标 题: 典型算法与ACM题目解析(02)—有向图的强连通分量
发信站: 武汉白云黄鹤站 (2006年08月17日20:17:44 星期四), 站内信件
这道题是POJ的2186题,题意是说,有一群牛,总数为N(N<=10000),题目数据给出牛之间的
关系,比如说1仰慕2,2仰慕3等等,设这种仰慕是可以传递的,如果1仰慕2,那么1也会同
时仰慕2仰慕的那些牛,如果一头牛被所有的牛都仰慕,那么它将是最受欢迎的牛,题目要
求的是有多少牛是"最受欢迎的"。
这道题目大家第一眼看到可能感觉直接模拟,但是由于数据量巨大,模拟的话肯定是过不
了的,而且题目中还会出现环路的情况,比如1=>2,2=>3,3=>1,所以这解这道题最好的方
法是使用有向图的强连通分量。
在同一个强连通分量里的所有的牛之间是互相仰慕的,我们将其缩为一点,并且只记录这
一点的牛的数量,如果有最受欢迎的牛存在,那么这个图将是连通图,并且出度为零的点
只有一个,我们可以用并查集来判是否连通,然后计算每个节点的出度,即可求出最受欢
迎的牛的数量。
求强连通分量有三种算法,分别是Kosaraju算法,Gabow算法和Tarjan算法,其中Kosaraju
算法要对原图和逆图都进行一次DFS,而另外两种算法只要DFS一次就可以了
用了Gabow算法和Kosaraju算法各写了一遍
在时间上Gabow算法是122ms,Kosaraju算法是61ms
理论上Gabow算法要比Kosaraju快些的,因为Gabow算法只对原图进行一次DFS
而Kosaraju要进行两次
Gabow反而慢的原因可能是我用了STL里的stack
PS:我没看懂Gabow算法,完全是对着书上写的
代码如下:
Kosaraju算法
/*
求有向图的强连通分量的Kosaraju's algorithm
By Sempr ---- 2006.06.16
*/
#include <stdio.h>
#include <string.h>
#define G_size 100000
#define V_size 11000
typedef struct Graph
{
int id;
int next;
} Graph;
typedef struct Edge
{
int s, e;
} Edge;
Edge E[G_size];
Graph GA[G_size], GT[G_size];
int N, M;
int G_end;
int order[V_size], id[V_size], vis[V_size], in[V_size];
int cnt, scnt, pos;
void Insert(int s, int e) //建立原图和逆图
{
int p;
p = s;
while (GA[p].next)
p = GA[p].next;
GA[G_end].id = e;
GA[p].next = G_end;
p = e;
while (GT[p].next)
p = GT[p].next;
GT[G_end].id = s;
GT[p].next = G_end;
G_end++;
}
void DFST(int x) //对逆图进行搜索
{
int p, q;
vis[x] = 1;
p = GT[x].next;
while (p)
{
q = GT[p].id;
if (!vis[q])
DFST(q);
p = GT[p].next;
}
order[cnt++] = x;
}
void DFSA(int x) //对原图进行搜索
{
int p, q;
vis[x] = 1;
id[x] = cnt;
p = GA[x].next;
while (p)
{
q = GA[p].id;
if (!vis[q])
DFSA(q);
p = GA[p].next;
}
}
void Solve() //主要过程
{
int s, e;
int i;
memset(GA, 0, sizeof(GA));
memset(GT, 0, sizeof(GT));
memset(E, 0, sizeof(E));
G_end = N + 1;
for (i = 0; i < M; i++)
{
scanf("%d %d", &s, &e);
E[i].s = s - 1;
E[i].e = e - 1;
Insert(s - 1, e - 1);
}
memset(vis, 0, sizeof(vis));
cnt = 0;
for (i = 0; i < N; i++)
{
if (!vis[i])
{
DFST(i);
}
}
memset(vis, 0, sizeof(vis));
cnt = 0;
for (i = N - 1; i >= 0; i--)
{
if (!vis[order[i]])
{
DFSA(order[i]);
cnt++;
}
}
for (i = 0; i < M; i++)
{
s = id[E[i].s];
e = id[E[i].e];
if (s != e)
{
in[s]++;
}
}
scnt = cnt;
cnt = 0;
for (i = 0; i < scnt; i++)
{
if (in[i] == 0)
{
pos = i;
cnt++;
}
}
if (cnt != 1)
{
printf("0\n");
}
else
{
cnt = 0;
for (i = 0; i < N; i++)
{
if (in[id[i]] == pos)
{
cnt++;
}
}
printf("%d\n", cnt);
}
}
int main()
{
while (EOF != scanf("%d %d", &N, &M))
Solve();
return 0;
}
Gabow算法
/*
求有向图的强连通分量的Gabow's algorithm
By Sempr ---- 2006.06.14
*/
#include <stdio.h>
#include <algorithm>
#include <stack>
#define size 11000
using namespace std;
int N, M;
typedef struct Node
{
int id;
int next;
} Node;
typedef struct Edge
{
int s, e;
}Edge;
Edge E[size * 6];
Node G[size * 7];
int pre[size], id[size];
typedef stack<int> Stack;
Stack S, path;
int end;
int cnt, scnt;
int vis[size];
int in[size];
void Insert(int s, int e)
{
int p = s;
while (G[p].next)
{
p = G[p].next;
if (G[p].id == e)
{
return;
}
}
G[p].next = end;
G[end].id = e;
end++;
}
void scR(int w)
{
int v;
int p, t;
pre[w] = cnt++;
S.push(w);
path.push(w);
p = G[w].next;
while (p)
{
t = G[p].id;
p = G[p].next;
if (pre[t] == -1)
scR(t);
else if (id[t] == -1)
while (pre[path.top()] > pre[t])
path.pop();
}
if (path.top() == w)
path.pop();
else
return;
do
{
id[v = S.top()] = scnt;
S.pop();
}
while (v != w);
scnt++;
}
void Gabow()
{
int i;
memset(pre, -1, sizeof(pre));
memset(id, -1, sizeof(id));
cnt = 0;
scnt = 0;
while (!S.empty())
S.pop();
while (!path.empty())
path.pop();
for (i = 1; i <= N; i++)
{
if (pre[i] == -1)
{
scR(i);
}
}
}
void DFS(int w, int d)
{
int p = G[w].next;
d++;
pre[w] = 1;
if (d > cnt)
{
cnt = d;
}
while (p)
{
if (pre[G[p].id] != 1)
{
DFS(G[p].id, d);
}
p = G[p].next;
}
}
void Solve()
{
int i, s, e;
int pos;
memset(G, 0, sizeof(G));
end = N + 10;
memset(in, 0, sizeof(in));
for (i = 0; i < M; i++)
{
scanf("%d %d", &s, &e);
E[i].s = s;
E[i].e = e;
Insert(s, e);
}
Gabow();
memset(G, 0, sizeof(G));
memset(pre, 0, sizeof(pre));
end = scnt + 10;
for (i = 0; i < M; i++)
{
s = id[E[i].s];
e = id[E[i].e];
if (s != e)
{
in[s]++;
}
}
cnt = 0;
for (i = 0; i < scnt; i++)
{
if (in[i] == 0)
{
pos = i;
cnt++;
}
}
if (cnt != 1)
{
printf("0\n");
}
else
{
cnt = 0;
for (i = 1; i <= N; i++)
{
if (in[id[i]] == pos)
{
cnt++;
}
}
printf("%d\n", cnt);
}
}
int main()
{
while (scanf("%d %d", &N, &M) != EOF)
Solve();
}
return 0;
}
--
▁▃▄▅▃▂▁ /╲_ .
__ ╱/ ╲╲╱╲ ヌ ゑ
╱ ╳ ; /▁▂▃▄▃▂▁ リ θ 一山一水一圣人
/ \ ╲╱ \ / : ╲────╮ ——白雲黃鶴ShanDong版
╱\ \╱╳╲ :: |/ ﹨: ╲──╮╰────────────╮
/ . \ /;╲ /\/; ; :﹨ ╲ ╰────────────╮╰───
※ 来源:·武汉白云黄鹤站 bbs.whnet.edu.cn·
--
Science is what we understand well enough to explain to a computer.
Art is everything else we do.
———— Donald E. Knuth
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.14.224]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店