Hdu 1269 迷宫城堡

 

强连通分量Tarjan模板,明天再来理解下。顺便学学二分图匹配,最小割,最大流等,接触了大概有一个多月了,看了好久的论文,不过大部分都没实现过。

CODE:

 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using  namespace std;

#define MAXN 10010
#define MAXM 100010

struct Edge
{
       int v, next;  
}edge[MAXM];     // 边结点数组 

int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXM];
//  first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组 
// Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号 
int instack[ 10010];   //  instack[]为是否在栈中的标记数组 
int n, m, cnt, scnt, top, tot;

void init()
{
    cnt =  0;
    scnt = top = tot =  0;     // 初始化连通分量标号,次序计数器,栈顶指针为0 
    memset(first, - 1sizeof(first));
    memset(DFN,  0sizeof(DFN));    // 结点搜索的次序编号数组为0,同时可以当是否访问的数组使用 
}

void read_graph( int u,  int v)  // 构建邻接表 
{
     edge[tot].v = v;
     edge[tot].next = first[u];
     first[u] = tot++;
}

void Tarjan( int v)        // Tarjan算法求有向图的强连通分量 
{
      int min, t;
     DFN[v] = Low[v] = ++tot;     // cnt为时间戳
     instack[v] =  1;     // 标记在栈中 
     stack[top++] = v;       // 入栈 
      for( int e = first[v]; e != - 1; e = edge[e].next)
     {    // 枚举v的每一条边 
            int j = edge[e].v;    // v所邻接的边 
            if(!DFN[j])
           {    // 未被访问 
               Tarjan(j);     // 继续向下找 
                if(Low[v] > Low[j]) Low[v] = Low[j];   //  更新结点v所能到达的最小次数层 
           }
            else  if(instack[j] && DFN[j] < Low[v])
           {    // 如果j结点在栈内, 
               Low[v] = DFN[j];
           }
     }
      if(DFN[v] == Low[v])
     {      // 如果节点v是强连通分量的根 
           scnt++;    // 连通分量标号加1 
            do
           {
               t = stack[--top];    // 退栈 
               instack[t] =  0;    // 标记不在栈中 
               Belong[t] = scnt;    // 出栈结点t属于cnt标号的强连通分量 
           } while(t != v);   // 直到将v从栈中退出 
     }
}

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;
            scanf( " %d%d ", &u, &v);
            read_graph(u, v);
        }
        solve();      // 求强连通分量 
         if(scnt ==  1) printf( " Yes\n ");   // 只有一个强连通分量,说明此图各个结点都可达
         else printf( " No\n ");
    }
     return  0;
}

 

CODE:

 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using  namespace std;

#define MAXN 10010
#define MAXM 100010 

struct Edge
{
     int v, w, next;
}edge[MAXM];

int first[MAXN], stack[MAXN], ins[MAXN], dfn[MAXN], low[MAXN];
int belong[MAXM];

int n, m;
int cnt, scnt, tot, top;

void init()
{
    cnt =  0;
    tot = scnt = top =  0;
    memset(ins,  0sizeof(ins));
    memset(first, - 1sizeof(first));
    memset(dfn,  0sizeof(dfn));
}

void read_graph( int u,  int v)
{
    edge[cnt].v = v;
    edge[cnt].next = first[u], first[u] = cnt++;
}

void Tarjan( int u)
{
     int t;
    dfn[u] = low[u] = ++tot;
    stack[top++] = u;
    ins[u] =  1;
     for( int e = first[u]; e != - 1; e = edge[e].next)
    {
         int v = edge[e].v;
         if(!dfn[v])
        {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
         else  if(ins[v])
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
     if(dfn[u] == low[u])
    {
        scnt++;
         do
        {
            t = stack[--top];
            ins[t] =  0;
            belong[t] = scnt;
        } while(t != u);
    }
}

void solve()
{
     for( int i =  1; i <= n; i++)     if(!dfn[i])
        Tarjan(i);
}

int main()
{
     while(scanf( " %d%d ", &n, &m) && (n || m))
    {
        init();
         while(m--)
        {
             int u, v;
            scanf( " %d%d ", &u, &v);
            read_graph(u, v);
        }
        solve();
         if(scnt ==  1) printf( " Yes\n ");
         else printf( " No\n ");
    }
     return  0;
}

 

你可能感兴趣的:(HDU)