HDU 1269(Tarjan 算法+静态邻接表)
以下是某牛blog上关于算法描述的转载,本人编写代码仅有的算法资料也就是这些.
收缩有向图中的强连通分量大约是图论的线性算法中最具技巧性一种了。我们的首要目的是对于每个顶点设定一个Belong值,也就是它从属于哪个顶点所代表的强连通分量,至于重新建立图的边,不过是将所有边扫描一遍看是否在新图中出现而已,比较容易。
下面是利用一遍DFS求强连通分量的方法:对于每个顶点,设立Num、Low、Used、Alive四个属性,一个Stack保存当前正在被遍历的顶点;每访问一个顶点,将它的Num和Low设立为当前时间戳,Used、Alive设为True,并将顶点入栈,对于它的每条边,若边的终点未Used,则访问,而后用终点的Low值更新它的Low值,对于每个Used且Alive的终点,用它的Num值更新当前值;访问完毕当前顶点后,若Low与Num相等,说明找到了一个强连通分量,它包括栈中所有在当前顶点上方的顶点,将它们出栈并记下Belong值,出栈的顶点的Alive要置为false。
注意这里的Low值与求割顶和桥时的Low值的定义不太相同,它是与当前顶点双连通的最低顶点,所以才要用Alive来标记是否能到达当前顶点。
转载结束.....
强连通分量的判定对图算法的优化有很大的意义,缩点与不缩点在效率上有很大的差别,许多问题在DFS下变的十分容易,如时间戳等标记的技巧使用,辅之以白色路径定理,在很多图论算法中有着重要的应用.
本算法的基本思想认为dfs经过的路径中,若有一点可返回访问过的点,则到该点访问过的所有点在一个强连通分量之中。注意理解喔~~~
以下是1269的代码:
#include <iostream>
#include <stack>
using namespace std;
typedef struct
{
long v,next;
}Edge;
typedef struct
{
long Num;
long Used;
long Alive;
long Low;
long belong;
void init(long pos)
{
Num=Used=Alive=Low=0;
belong=pos;
}
}Node;
const long MAXN=100010;
long N,M;//点,边
Edge e[MAXN];//边数组
long p[MAXN/10];//辅助数组
Node vec[MAXN/10];//点
stack<long> s;
long Permit;//时间戳
inline void init()
{
long i;
while (!s.empty())
{
s.pop();
}
Permit=0;
memset(p,-1,sizeof(p));
for (i=0;i<=N;++i)
{
vec[i].init(i);
}
for (i=0;i<M;++i)
{
long from,to;
scanf("%ld %ld",&from,&to);
e[i].next=p[from];
e[i].v=to;
p[from]=i;
}
}
inline void update(long &a,long b)
{
if(a>b) a=b;
}
inline void dfs(long pos)
{
s.push(pos);
vec[pos].Low=vec[pos].Num=++Permit;
vec[pos].Used=vec[pos].Alive=true;
long j;
for (j=p[pos];j!=-1;j=e[j].next)
{
long to=e[j].v;
if (vec[to].Used)
{
if (vec[to].Alive)
{
update(vec[pos].Low,vec[to].Num);
}
}
else
{
dfs(to);
update(vec[pos].Low,vec[to].Low);
}
}
if (vec[pos].Num==vec[pos].Low)
{
long t;
while ((t=s.top())!=pos)
{
vec[t].belong=pos;
vec[t].Alive=false;
s.pop();
}
vec[pos].belong=pos;
vec[pos].Alive=false;
s.pop();
}
}
inline void Tarjan()
{
long i;
for (i=1;i<=N;++i)
{
if (!vec[i].Used)
{
dfs(i);
}
}
}
int main()
{
while (scanf("%ld %ld",&N,&M)!=EOF)
{
if (N==0&&M==0)
{
break;
}
init();
Tarjan();
long i;
long t=vec[1].belong;
bool doit=true;
for (i=2;i<=N;++i)
{
if (vec[i].belong!=t)
{
doit=false;
break;
}
}
if (doit)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}
#include <stack>
using namespace std;
typedef struct
{
long v,next;
}Edge;
typedef struct
{
long Num;
long Used;
long Alive;
long Low;
long belong;
void init(long pos)
{
Num=Used=Alive=Low=0;
belong=pos;
}
}Node;
const long MAXN=100010;
long N,M;//点,边
Edge e[MAXN];//边数组
long p[MAXN/10];//辅助数组
Node vec[MAXN/10];//点
stack<long> s;
long Permit;//时间戳
inline void init()
{
long i;
while (!s.empty())
{
s.pop();
}
Permit=0;
memset(p,-1,sizeof(p));
for (i=0;i<=N;++i)
{
vec[i].init(i);
}
for (i=0;i<M;++i)
{
long from,to;
scanf("%ld %ld",&from,&to);
e[i].next=p[from];
e[i].v=to;
p[from]=i;
}
}
inline void update(long &a,long b)
{
if(a>b) a=b;
}
inline void dfs(long pos)
{
s.push(pos);
vec[pos].Low=vec[pos].Num=++Permit;
vec[pos].Used=vec[pos].Alive=true;
long j;
for (j=p[pos];j!=-1;j=e[j].next)
{
long to=e[j].v;
if (vec[to].Used)
{
if (vec[to].Alive)
{
update(vec[pos].Low,vec[to].Num);
}
}
else
{
dfs(to);
update(vec[pos].Low,vec[to].Low);
}
}
if (vec[pos].Num==vec[pos].Low)
{
long t;
while ((t=s.top())!=pos)
{
vec[t].belong=pos;
vec[t].Alive=false;
s.pop();
}
vec[pos].belong=pos;
vec[pos].Alive=false;
s.pop();
}
}
inline void Tarjan()
{
long i;
for (i=1;i<=N;++i)
{
if (!vec[i].Used)
{
dfs(i);
}
}
}
int main()
{
while (scanf("%ld %ld",&N,&M)!=EOF)
{
if (N==0&&M==0)
{
break;
}
init();
Tarjan();
long i;
long t=vec[1].belong;
bool doit=true;
for (i=2;i<=N;++i)
{
if (vec[i].belong!=t)
{
doit=false;
break;
}
}
if (doit)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}