HDU 1269 迷宫城堡

Kosaraju算法求有向图强连通分量,时间复杂度$O(V+E)$。

两次dfs,第一次按原图dfs,用个vector数组存储dfs序,越晚搜到的点dfs序越大。
第二次按反图(所有边反向)dfs,先搜索第一次dfs序大的,然后把每个点记录其强连通分量的编号。

本题要求有向图中任意两个点都连通,即整个图中强连通分量个数为1。

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10;
int n,m,cnt,scc[N];
vector<int>g[N]; // 原图
vector<int>rg[N];// 反图
vector<int>s; // 按原图dfs序存储
bool vis[N];
void dfs1(int u)
{
    if(vis[u])return;
    vis[u]=1;
    int sz=g[u].size();
    for(int i=0;i<sz;i++)
        dfs1(g[u][i]);
    s.push_back(u);
}
void dfs2(int u)
{
    if(scc[u])return;
    scc[u]=cnt;
    int sz=rg[u].size();
    for(int i=0;i<sz;i++)
        dfs2(rg[u][i]);
}
bool judge()
{
    memset(vis,0,sizeof(vis));
    memset(scc,0,sizeof(scc));
    s.clear();
    cnt=0;
    for(int i=1;i<=n;i++)
        if(!vis[i])dfs1(i);
    for(int i=n-1;i>=0;i--) // 从第一次dfs序大的点搜索它的强连通分量
    {
        int u=s[i];
        if(!scc[u])
        {
            cnt++;
            if(cnt>1)return 0;
            dfs2(u);
        }
    }
    return cnt==1;
}
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m&&!(n==0&&m==0))
    {
        for(int i=1;i<=n;i++)
        {
            g[i].clear();
            rg[i].clear();
        }
        int x,y;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>y;
            g[x].push_back(y);
            rg[y].push_back(x);
        }
        if(judge())printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

参考:《算法竞赛 入门到进阶》P232
在这里插入图片描述