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 ;
}

转载于:https://www.cnblogs.com/zhuangli/archive/2008/08/23/1274821.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值