HDU1269 迷宫城堡,Tarjan算法入门

首先了解以下名词:
强连通:两个顶点a、b,若a有路径通向b、b亦有路径通向a,则称a、b两点 强连通(strongly connected)。
强连通图:如果有向图 G的任意两个顶点都强连通,称G是一个强连通图。
强连通分量:非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
后向边 :子孙指向祖先的边

Tarjan算法思想:
在深搜的基础下,遍历当前点的所有子孙,找出该点与子孙中所能找到的最早的祖先。

1.(设当前点为pos)time[pos]=Time 能进行深搜表明该点是第一次访问,故time[pos]可确定
2. low[pos]=Time 暂时认为能找到的最早祖先是自己
3. 遍历所有从pos出发所能到达的点 i:
①若点 i 未被访问:对点 i 重复从1.开始的操作以确定low[i]。而后取low[pos]=min( low[pos], low[i] )
②若点 i 在访问中:取low[pos]=min( low[pos], time[i] )
③若点 i 已访问过:什么都不做(它的子孙所在的最大强连通分量已经确定了)
4. 若low[pos]依然是pos,说明pos及其子孙构成了一个强连通分量,计数器应加一
5. 将点pos的状态设置为已访问

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define max(a, b)  (((a) > (b)) ? (a) : (b))
#define min(a, b)  (((a) < (b)) ? (a) : (b))
#define N 10020
using namespace std;
struct node{
    int point;
    node *next;
};
int con,n;
int time[N];    //访问该点时的时间(间接指出了先后关系)
int low[N];     //代表该点所能找到的最早祖先(即最大强连通分量)
node mapa[N];   //邻接表的首结点数组
char state[N];  //代表对应点的状态:0代表未被访问过、1代表正在访问、2表示访问完毕

/**
    @参1:在第pos个点执行tarjan操作 参数2:访问pos点时的时间
*/
void dfs_tarjan(int pos,int Time)
{
    node *p;
    time[pos]=Time; //得到访问时间
    state[pos]=1;   //标记为正在访问
    low[pos]=Time;
    for(p=&mapa[pos];p->next;p=p->next)
    {
        int i=p->next->point;
        if(state[i]==0)     //未访问
        {
            dfs_tarjan(i,Time+1);
            low[pos]=min(low[pos],low[i]);  //在这之前以通过深搜得出了子孙的“low”,取二者最早祖先即可
        }else if(state[i]==1)//i点正在访问
            low[pos]=min(low[pos],time[i]); //最早祖先当然是 目前结果 和 i的最早祖先 中最早的那个啦(求最大嘛)
    }
    if(low[pos]==time[pos]) //若pos的所有子孙访问完了,pos所能访问到的最早祖先还是自己,说明自己极其子孙构成了一个最大强连通分量
         con++;
    state[pos]=2;   //该点访问结束
}
int main()
{
    IN;
    int i,m;
    int a,b,num;
    node *temp;
    while(cin>>n>>m,m||n)
    {
        for(i=1;i<=n;i++)
            mapa[i].next=NULL;
        while(m-->0)
        {
            cin>>a>>b;
            temp=(node*)malloc(sizeof(node));
            temp->point=b;
            temp->next=mapa[a].next;
            mapa[a].next=temp;
        }
        memset(state+1,0,sizeof(char)*(n+1));
        con=0;
        for(i=1;i<=n;i++)   //遍历每一个点
            if(state[i]!=2) //若未被访问执行深搜操作
                dfs_tarjan(i,0);
        if(con==1)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值