强连通图的算法【Tarjan】+ 【HDU1269】 迷宫城堡

参考博客:https://blog.csdn.net/justlovetao/article/details/6673602
                  https://blog.csdn.net/qq_16234613/article/details/77431043     (代码含有注释)

问题:

for(int i=head[s]; i!=-1; i=edge[i].p)
{
    int e=edge[i].e;
    if(!dfn[e])
    {
        tanjar(e);
        low[s]=min(low[s],low[e]);
    }
    else
    {
        if(instack[e])    ///为什么要进行判断
            low[s]=min(low[s],dfn[e]);
    }
}

将判断去掉和不去掉会得到不同强连通分量数量,如果不加  if(instack[e]) 那么 dfn[5]!=low[5],就会失去一个强连通分量 5.

例题:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=998424353;
const double INF=1e15;
const int maxn=1e5+5;

int n,m;

struct node
{
    int e;
    int p;
}edge[100005];
int sign,head[10005];

int time;
int dfn[10005],low[10005];
int Stack[10005],instack[10005],top;
int cnt;

void init()
{
    cnt=0;
    sign=0;
    time=0;
    top=0;
    for(int i=1;i<=10000;i++)
    {
        head[i]=-1;
        dfn[i]=low[i]=0;
        instack[i]=0;
    }
}

void add_edge(int s,int e)
{
    edge[++sign]=node{e,head[s]};
    head[s]=sign;
}

void tanjar(int s)
{
    dfn[s]=low[s]=++time;
    instack[s]=1;
    Stack[++top]=s;
    for(int i=head[s];i!=-1;i=edge[i].p)
    {
        int e=edge[i].e;
        if(!dfn[e])
        {
            tanjar(e);
            low[s]=min(low[s],low[e]);
        }
        else
        {
            if(instack[e])
                low[s]=min(low[s],dfn[e]);
        }
    }
    int t;
    if(dfn[s]==low[s])
    {
        cnt++;
        do
        {
            t=Stack[top--];
            instack[t]=0;
        }while(s!=t);
    }
}
int main()
{
    int s,e;
    while(scanf("%d %d",&n,&m)!=EOF,n+m)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&s,&e);
            add_edge(s,e);
        }
        tanjar(1);
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                tanjar(i);
        }
        printf(cnt==1?"Yes\n":"No\n");
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值