HDU11269 迷宫城堡(强连通分量)

迷宫城堡

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 26892    Accepted Submission(s): 11446


Problem Description
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
 
Input
输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
 
Output
对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
 
Sample Input
3 3 1 2 2 3 3 1 3 3 1 2 2 3 3 2 0 0
 
Sample Output
Yes No
 
Author
Gardon
 
Source
 
Recommend
lxj   |   We have carefully selected several similar problems for you:  1233 1142 1217 1162 1102 

题解:求强连通分量,如果唯一则YES,否则为NO。模板题。
 
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define pil pair<int,ll>
#define fi head
#define se second
#define pb push_back
#define mkp make_pair
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3fll;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;    
}
const int maxn=10010;//
const int maxm=100010;//
struct Edge{
    int v,nxt;  
}edge[maxm];   
int head[maxn],Stack[maxn],dfn[maxn],low[maxn],Belong[maxm];
int instack[maxn];
int n,m,cnt,Blocks,top,tot;
void Init()
{
    cnt=0;
    Blocks=top=tot=0;//初始化连通分量标号,次序计数器,栈顶指针为0 
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
}
void AddEdge(int u,int v)
{
     edge[tot].v=v;
     edge[tot].nxt=head[u];
     head[u]=tot++;
}
void Tarjan(int u)
{
     int min,t;
     dfn[u]=low[u]=++tot; //cnt为时间戳
     instack[u]=1;    //标记在栈中 
     Stack[top++]=u;      //入栈 
     for(int e=head[u];~e;e=edge[e].nxt)
     {   //枚举v的每一条边 
           int v=edge[e].v; //u所邻接的边 
           if(!dfn[v])
           {   //未被访问 
               Tarjan(v);    //继续向下找 
               if(low[u]>low[v]) low[u]=low[v];//更新结点u所能到达的最小次数层 
           }
           else if(instack[v]&&dfn[v]<low[u])//如果v结点在栈内
               low[u]=dfn[v];
     }
     if(dfn[u]==low[u])
     {     //如果节点v是强连通分量的根 
           Blocks++;   //连通分量标号加1 
           do
           {
               t=Stack[--top]; //退栈 
               instack[t]=0;//标记不在栈中 
               Belong[t]=Blocks; //出栈结点t属于Blocks标号的强连通分量 
           }while(t!=u);  //直到将u从栈中退出 
     }
}
void solve()
{
     for(int i=1;i<=n;++i)//枚举每个结点,搜索连通分量
        if(!dfn[i]) //未被访问 
           Tarjan(i);//则找i结点的连通分量 
}
 
int main()
{
    while(scanf("%d%d",&n,&m)&&(n||m))
    {
        Init();
        while(m--)
        {
            int u, v;
            u=read(); v=read();
            AddEdge(u,v);
        }
        solve();
        if(Blocks==1) printf("Yes
");  
        else printf("No
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/csushl/p/11306866.html