zoukankan      html  css  js  c++  java
  • 割点割边连通分量等连通性相关算法

    FloodFill

    不说了….大家都会写…..

     

     

    无向图割点

    我们使用DFS对每个点记录两个值:
      1) dfn[i]  表示点i是第几个DFS到的点.
      2) low[i]  表示从点i出发,经过点i的某个子孙节点(包括它自己),然后通过非树边绕回而取得的最小的dfn值.

     

    算法正确性依赖于如下定理:

      定理: 一个点x是割点,当且仅当满足下列条件之一:

        1) x是DFS搜索树的根,且x有多于1棵子树.

        2) x不是DFS搜索树的根,且存在一个节点v,满足:

            1. v是x在搜索树上的直接子节点;

            2. 在v及其子树中,没有任何一条边后向边指向x的祖先;

    注意无向图不存在横叉边(即从一颗子树连向另一棵子树,这两棵子树没有交集).

     

    有了如上定理,使用dfn与low可将其转化为:

      定理: 一个点x是割点,当且仅当满足下列条件之一:

        1) x是DFS搜索树的根,且x拥有多于1棵子树.

        2) x不是DFS搜索树的根,且存在一个节点v,满足:

            1.v是x在搜索树上的直接子节点;

            2.low[v] == dfn[x].

    满足条件的v可能有多个,删掉节点x所分离的连通块个数为满足条件的v的个数+1.

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <fstream>
      4 
      5 #include <cmath>
      6 #include <cstdlib>
      7 #include <algorithm>
      8 #include <cstring>
      9 
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 typedef unsigned int uint;
     13 typedef double db;
     14 
     15 int getint()
     16 {
     17     int res=0; char c=getchar(); bool m=false;
     18     while(c<'0' || c>'9') m=(c=='-'),c=getchar();
     19     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     20     return m ? -res : res;
     21 }
     22 
     23 const db eps=1e-18;
     24 bool feq(db a,db b)
     25 { return fabs(b-a)<eps; }
     26 
     27 using namespace std;
     28 
     29 const int INF=(1<<30)-1;
     30 
     31 struct edge
     32 {
     33     int in;
     34     edge*nxt;
     35 }pool[200000];
     36 edge*et=pool;
     37 edge*eds[1050];
     38 inline edge*addedge(int i,int j)
     39 { et->in=j; et->nxt=eds[i]; eds[i]=et++; }
     40 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     41 
     42 int n,m;
     43 bool used[1050];
     44 
     45 int dfn[1050];
     46 int low[1050];
     47 int cnt[1050];
     48 int f[1050];
     49 bool ins[1050];
     50 int cur;
     51 void DFS(int x)
     52 {
     53     used[x]=true;
     54     low[x]=dfn[x]=cur++;
     55 
     56     ins[x]=true;
     57 
     58     FOREACH_EDGE(i,x)
     59     {
     60         if(!used[i->in])
     61         {
     62             DFS(i->in);
     63             if(low[i->in]==dfn[x]) cnt[x]++;
     64             low[x]=min(low[x],low[i->in]);
     65         }else
     66         {
     67             if(i->in!=f[x])
     68             low[x]=min(low[x],dfn[i->in]);
     69         }
     70     }
     71 
     72     ins[x]=false;
     73 }
     74 
     75 void INIT()
     76 {
     77     et=pool;
     78     memset(eds,0,sizeof(eds));
     79     memset(dfn,0,sizeof(dfn));
     80     memset(low,0,sizeof(low));
     81     memset(cnt,0,sizeof(cnt));
     82     memset(f,0,sizeof(f));
     83     memset(used,0,sizeof(used));
     84 }
     85 
     86 int main()
     87 {
     88     int a,b,T=1;
     89     while(a=getint())
     90     {
     91         b=getint();
     92         INIT();
     93         addedge(a,b);
     94         addedge(b,a);
     95         while(a=getint())
     96         {
     97             b=getint();
     98             addedge(a,b);
     99             addedge(b,a);
    100         }
    101 
    102         cur=1;
    103         f[1]=1;
    104         DFS(1);
    105 
    106         printf("Network #%d\n",T);
    107 
    108         int tot=0;
    109 
    110 
    111         if(cnt[1]>=2)
    112             printf("  SPF node %d leaves %d subnets\n",1,cnt[1]),tot++;
    113 
    114         for(int i=2;i<=1000;i++)
    115         {
    116             if(cnt[i]!=0)
    117             {
    118                 printf("  SPF node %d leaves %d subnets\n",i,cnt[i]+1);
    119                 tot++;
    120             }
    121         }
    122 
    123         if(!tot)
    124             printf("  No SPF nodes\n");
    125 
    126         printf("\n");
    127 
    128         T++;
    129     }
    130     return 0;
    131 }
    View Code

     

    强连通分量

    dfn和low跟上边一样,没有什么区别.....

    定理: 强连通分量在搜索树上表现为一棵子树.

    使用那个栈的目的是去除一整棵子树.注意low值并不代表强连通分量的子树的根.

    下面是AC BZOJ 1051的代码.

    一道裸的求强连通分量.(为什么大家都是一眼题TAT我根本没想到啊这个做法....)

    struct edge
    {
        int in;
        edge*nxt;
    }pool[205000];
    edge*et=pool;
    edge*eds[50050];
    void addedge(int i,int j)
    { et->in=j; et->nxt=eds[i]; eds[i]=et++; }
    #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
    
    int block[50050],btot;
    
    int cnt;
    int dfn[50050];
    int low[50050];
    int s[50050],st;
    bool ins[50050];
    bool used[50050];
    void DFS(int x)
    {
        dfn[x]=low[x]=++cnt;
        s[st++]=x;
        used[x]=ins[x]=true;
        FOREACH_EDGE(i,x)
        {
            if(!used[i->in])
            {
                DFS(i->in);
                low[x]=min(low[x],low[i->in]);
            }
            else 
            if(ins[i->in])
                low[x]=min(low[x],dfn[i->in]);
        }
        
        if(dfn[x]==low[x])
        {
            btot++;
            int p;
            do
            {
                p=s[--st];
                ins[p]=false;
                block[p]=btot;
            }
            while(p!=x);
        }
    }
    
    
    int deg[50050];
    int n,m;
    
    int main()
    {
        n=getint();
        m=getint();
        for(int i=0;i<m;i++)
        {
            int a=getint()-1;
            int b=getint()-1;
            addedge(b,a);
        }
        
        for(int i=0;i<n;i++)
        if(!used[i]) DFS(i);
        
        for(int i=0;i<n;i++)
        FOREACH_EDGE(e,i)
        {
            if(block[i]!=block[e->in]) //not belong to the same block.
            deg[block[e->in]]++; //intake degree of block.
        }
        
        int resb=0;
        for(int i=1;i<=btot;i++)
        {
            if(deg[i]==0)
            {
                if(resb==0)
                resb=i;
                else
                {
                    printf("0\n");
                    return 0;
                }
            }
        }
        
        int res=0;
        for(int i=0;i<n;i++)
        if(block[i]==resb) res++;
        
        printf("%d\n",res);
        
        return 0;
    }
    View Code

    具体的做法,每头牛设一个点.

    牛A被其它所有牛认为是受欢迎的,等价于所有点都有到达点A的路径.

    等价于,如果我们把原图的边反过来(u,v)->(v,u),那么从A出发必定能到达其它所有点.

    我们把反过来的图先强连通分量缩点得到DAG(有向无环图). <--这里想不到TAT 是我做题少了么

    那么,那些受欢迎的牛,一定在DAG"开头"的位置,即入度为0的点(强连通分量)中.(如果入度不为0,比如说边(u,v)使得v的入度不为0,所以v必定不能到达u(否则就有u->v->u的环,就不是DAG了))

    于是,找到入度为0的强连通分量,特判一下是否唯一就好了(不唯一必无解,不能从一个入度为0的分量走到另一个入度为0的分量.).....

     

    另外一题 BZOJ 1179 APIO2009 ATM

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-20;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //==========================================================
     52 //==========================================================
     53 //==========================================================
     54 //==========================================================
     55 
     56 
     57 struct edge
     58 {
     59     int in;
     60     edge*nxt;
     61 }pool[4005000];
     62 edge*et=pool;
     63 edge*eds[1005000];
     64 edge*edp[1005000];
     65 void addedge(int i,int j)
     66 { et->in=j; et->nxt=eds[i]; eds[i]=et++; }
     67 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     68 
     69 int v[1005000];
     70 bool endp[1005000];
     71 
     72 int block[505000]; int btot=0;
     73 bool used[1005000];
     74 int low[505000];
     75 int dfn[505000]; int cnt=0;
     76 int ins[505000];
     77 int stk[505000]; int sp=0;
     78 void DFS(int x)
     79 {
     80     dfn[x]=low[x]=++cnt;
     81     used[x]=true;
     82     ins[x]=true;
     83     stk[sp++]=x;
     84     FOREACH_EDGE(i,x)
     85     {
     86         if(!used[i->in])
     87         {
     88             DFS(i->in);
     89             low[x]=min(low[x],low[i->in]);
     90         }
     91         else
     92         if(ins[i->in])
     93             low[x]=min(low[x],dfn[i->in]);
     94     }
     95     
     96     if(dfn[x]==low[x])
     97     {
     98         int p;
     99         do
    100         {
    101             p=stk[--sp];
    102             block[p]=btot;
    103             ins[p]=false;
    104         }
    105         while(p!=x);
    106         btot++;
    107     }
    108 }
    109 
    110 int n,m;
    111 int st;
    112 
    113 typedef pair<int,bool> pl;
    114 pl d[1005000];
    115 
    116 pl RSDFS(int x)
    117 {
    118     if(used[x]) return d[x];
    119     
    120     int res=0;
    121     bool ok=false;
    122     used[x]=true;
    123     
    124     FOREACH_EDGE(i,x)
    125     {
    126         pl s=RSDFS(i->in);
    127         if(s.second)
    128         {
    129             ok=true;
    130             res=max(res,s.first);
    131         }
    132     }
    133     
    134     return d[x]=pl(res+v[x],ok||endp[x]);
    135 }
    136 
    137 int main()
    138 {
    139     n=getint();
    140     m=getint();
    141     for(int i=0;i<m;i++)
    142     {
    143         int a=getint()-1;
    144         int b=getint()-1;
    145         addedge(a,b);
    146     }
    147     for(int i=0;i<n;i++)
    148     v[i]=getint();
    149     st=getint()-1;
    150     
    151     int h=getint();
    152     for(int i=0;i<h;i++)
    153     endp[getint()-1]=true;
    154     
    155     btot=n;
    156     for(int i=0;i<n;i++)
    157     if(!used[i]) DFS(i);
    158     
    159     for(int i=0;i<n;i++)
    160     {
    161         v[block[i]]+=v[i];
    162         endp[block[i]]|=endp[i];
    163     }
    164     st=block[st];
    165     
    166     for(int i=0;i<n;i++)
    167     FOREACH_EDGE(e,i)
    168     if(block[i]!=block[e->in])
    169     addedge(block[i],block[e->in]);
    170     
    171     printf("%d\n",RSDFS(st).first);
    172     
    173     return 0;
    174 }
    View Code

    做法是,缩点变成DAG,然后给每个DAG上的节点打上标记,DAG上节点的权值就是原图在这个分量里面的点的权值和,然后就可以DAG-DP了.....记录两个值,一个是从这个节点出发能拿到多少钱,另一个是从这个节点出发能不能走到终止节点(酒吧).

     

    转图真是坑爹啊.....

    还好BZOJ没卡栈,否则又要写一遍toposort......TAT

     

    无向图割边&双连通分量

    边拆点大法好.

    为每条边设一个点x,原图中(u,v)变成(u,x)和(x,v)两条无向边.

    然后跑割点就行了o(╯□╰)...

    下面是代码 AC VIJOS 1325

    题意是求割边条数,以及使得原图双连通需要添加的最少边数.

    后面一问,考虑双连通分量缩点后原图变成一棵树,每条树边都是割边,每条边最多能构建1个环(连接2个叶节点),所以答案是叶节点个数除以2上取整.

     给出的图是连通图.

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 
     34 //==============================================================================
     35 //==============================================================================
     36 //==============================================================================
     37 //==============================================================================
     38 
     39 
     40 struct edge
     41 {
     42     int in;
     43     edge*ptr;
     44     edge*nxt;
     45 }pool[100050];
     46 edge*et=pool;
     47 edge*eds[20050];
     48 void addedge(int a,int b)
     49 {
     50     et->ptr=et+1;
     51     et->in=b; et->nxt=eds[a]; eds[a]=et++;
     52     et->ptr=et-1;
     53     et->in=a; et->nxt=eds[b]; eds[b]=et++;
     54 }
     55 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     56 
     57 int n,m,q;
     58 
     59 int dfn[20050];
     60 int low[20050];
     61 bool used[20050];
     62 int curd;
     63 int cut[20050];
     64 
     65 void DFS(int x)
     66 {
     67     dfn[x]=low[x]=++curd;
     68     used[x]=true;
     69     
     70     FOREACH_EDGE(i,x)
     71     {
     72         if(!used[i->in])
     73         {
     74             DFS(i->in);
     75             low[x]=min(low[x],low[i->in]);
     76         }
     77         else
     78             low[x]=min(low[x],dfn[i->in]);
     79     
     80         if(low[i->in]==dfn[x])
     81         cut[x]=true;
     82     }
     83 }
     84 
     85 int block[20050];
     86 int btot;
     87 void FFA(int x)
     88 {
     89     if(cut[x] && x>=n) return ; //not go across a cut edge.
     90     block[x]=btot;
     91     used[x]=true;
     92     FOREACH_EDGE(i,x)
     93     if(!used[i->in])
     94     FFA(i->in);
     95 }
     96 
     97 int deg[20050];
     98 
     99 int main()
    100 {
    101     n=getint();
    102     m=getint();
    103     
    104     for(int i=0;i<m;i++)
    105     {
    106         int a,b;
    107         a=getint()-1;
    108         b=getint()-1;
    109         addedge(a,n+i);
    110         addedge(b,n+i);
    111     }
    112     
    113     DFS(0);
    114     
    115     //Color Blocks.
    116     memset(used,0,sizeof(bool)*(n+m+1));
    117     for(int i=0;i<n;i++)
    118     if(!used[i]) { btot++; FFA(i); }
    119     
    120     //Count degree.
    121     for(int i=n;i<n+m;i++)
    122     if(cut[i]) FOREACH_EDGE(e,i)
    123     deg[block[e->in]]++;
    124     
    125     int lcnt=0;
    126     //Count leaves.
    127     for(int i=1;i<=btot;i++)
    128     if(deg[i]==1) lcnt++;
    129     
    130     int ccnt=0;
    131     //Count cuts.
    132     for(int i=n;i<n+m;i++)
    133     if(cut[i]) ccnt++;
    134     
    135     printf("%d\n%d\n",ccnt,(lcnt+1)/2);
    136     
    137     return 0;
    138 }
    View Code

     

     

    割边还有一种无需对图进行转换的算法.

    AC POJ 3352 其实跟VIJOS1325是一个样的...

    WA了两发....一是多组数据(题目写了吗?!)....二是根节点的割点判定要特别处理.....

     一条边(u,v)是割边,当且仅当满足一下条件之一:

        1) u与v其中一个点的度为1.

        2) u与v均为割点.

    哎不对啊.......考虑一个三角形,选两个顶点另接两个点......

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-32;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 struct edge
     58 {
     59     int in;
     60     edge*nxt;
     61     bool cut;
     62 }pool[50050];
     63 edge*et;
     64 edge*eds[10050];
     65 void addedge(int a,int b)
     66 {
     67     et->in=b; et->nxt=eds[a]; eds[a]=et++;
     68     et->in=a; et->nxt=eds[b]; eds[b]=et++;
     69 }
     70 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     71 
     72 
     73 int n,m;
     74 
     75 int low[10050];
     76 bool used[10050];
     77 int dfn[10050];
     78 bool iscut[10050];
     79 int dc=0;
     80 void DFS(int x)
     81 {
     82     dfn[x]=low[x]=++dc;
     83     used[x]=true;
     84     
     85     int tot=0;
     86     FOREACH_EDGE(i,x)
     87     {
     88         if(!used[i->in])
     89         {
     90             DFS(i->in);
     91             low[x]=min(low[x],low[i->in]);
     92         }
     93         else
     94             low[x]=min(low[x],dfn[i->in]);
     95         
     96         if(low[i->in]==dfn[x]) iscut[x]=true;
     97     
     98         tot++;
     99     }
    100     
    101     if(x==0) if(tot>1) iscut[x]=true; else iscut[x]=false;
    102 }
    103 
    104 int deg[10050];
    105 
    106 int block[10050];
    107 int btot;
    108 int cnt[10050];
    109 
    110 void FFA(int x)
    111 {    
    112     if(block[x]) return ;
    113     block[x]=btot;
    114     FOREACH_EDGE(i,x)
    115     if(!i->cut) FFA(i->in);
    116 }
    117 
    118 
    119 int main()
    120 {
    121 while(scanf("%d%d",&n,&m)>0)
    122 {
    123     et=pool;
    124     memset(eds,0,sizeof(int)*(n+1));
    125     memset(low,0,sizeof(int)*(n+1));
    126     memset(dfn,0,sizeof(int)*(n+1));
    127     memset(used,0,sizeof(bool)*(n+1));
    128     memset(deg,0,sizeof(int)*(n+1));
    129     memset(block,0,sizeof(int)*(n+1));
    130     memset(cnt,0,sizeof(int)*(n+1));
    131     dc=btot=0;
    132     
    133     for(int i=0;i<m;i++)
    134     {
    135         int a,b;
    136         a=getint()-1;
    137         b=getint()-1;
    138         addedge(a,b);
    139         deg[a]++;
    140         deg[b]++;
    141     }
    142     
    143     DFS(0);
    144     
    145     for(int i=0;i<n;i++)
    146     FOREACH_EDGE(e,i)
    147     if( deg[e->in]==1 || deg[i]==1 || (iscut[e->in] && iscut[i]) )
    148     e->cut=true;
    149     
    150     memset(used,0,sizeof(bool)*(n+1));
    151     for(int i=0;i<n;i++)
    152     if(block[i]==0) { ++btot; FFA(i); }
    153     
    154     for(int i=0;i<n;i++)
    155     FOREACH_EDGE(e,i)
    156     if(e->cut) cnt[block[i]]++;
    157     
    158     int tot=0;
    159     for(int i=1;i<=btot;i++)
    160     if(cnt[i]==1) tot++;
    161     
    162     printf("%d\n",(tot+1)/2);
    163 }
    164 
    165     return 0;
    166 }
    View Code

    连通分量嘛,就是把所有割边标记好,然后跑一边FloodFill染色就好啦o(╯□╰)o

    还是边拆点大法好

    AC VIJOS 1769

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42  
     43 db eps=1e-80;
     44 inline bool feq(db a,db b)
     45 { return fabs(a-b)<eps; }
     46 
     47 template<typename Type>
     48 inline Type avg(const Type a,const Type b)
     49 { return a+((b-a)/2); }
     50 
     51 //===================================================================
     52 //===================================================================
     53 //===================================================================
     54 //===================================================================
     55 
     56 
     57 struct edge
     58 {
     59     int in;
     60     edge*nxt;
     61 }pool[1205000];
     62 edge*et=pool;
     63 edge*eds[405000];
     64 void addedge(int a,int b)
     65 {
     66     et->in=b; et->nxt=eds[a]; eds[a]=et++;
     67     et->in=a; et->nxt=eds[b]; eds[b]=et++;
     68 }
     69 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     70 
     71 
     72 int n,m,ac,bc,ntot;
     73 int ast,bst;
     74 
     75 
     76 bool iscut[2][405000];
     77 
     78 int low[405000];
     79 int dfn[405000],cnt=0;
     80 bool used[405000];
     81 
     82 int ign,lbp;
     83 void DFS(int x)
     84 {
     85     dfn[x]=low[x]=++cnt;
     86     used[x]=true;
     87     
     88     FOREACH_EDGE(i,x)
     89     if(i->in!=ign)
     90     {
     91         if(!used[i->in]) 
     92         {
     93             DFS(i->in);
     94             low[x]=min(low[x],low[i->in]);
     95         }
     96         else
     97             low[x]=min(low[x],dfn[i->in]);
     98     
     99         if(low[i->in]==dfn[x])
    100             iscut[lbp][x]=true;
    101     }
    102 }
    103 
    104 //blocks define
    105 #define EDGENODE(i) ((i)+n+2)
    106 
    107 int ablock[205000];
    108 int bblock[205000];
    109 
    110 int main()
    111 {
    112     n=getint();
    113     m=getint();
    114     ac=getint();
    115     bc=getint();
    116     ntot=n+m+2;
    117     
    118     ast=n;
    119     bst=n+1;
    120     
    121     for(int i=0;i<ac;i++) ablock[i]=getint()-1;
    122     for(int i=0;i<bc;i++) bblock[i]=getint()-1;
    123     
    124     for(int i=0;i<m;i++)
    125     {
    126         int a,b;
    127         a=getint()-1;
    128         b=getint()-1;
    129         addedge(a,EDGENODE(i));
    130         addedge(b,EDGENODE(i));
    131     }
    132     
    133     
    134     //deal with A.
    135     ign=bst; lbp=0;
    136     for(int i=0;i<ac;i++)
    137     addedge(ast,ablock[i]);
    138     DFS(ast);
    139     
    140     memset(low,0,sizeof(int)*(ntot+1));
    141     memset(dfn,0,sizeof(int)*(ntot+1));
    142     memset(used,0,sizeof(bool)*(ntot+1));
    143     cnt=0;
    144     
    145     ign=ast; lbp=1;
    146     for(int i=0;i<bc;i++)
    147     addedge(bst,bblock[i]);
    148     DFS(bst);
    149     
    150     int cnt=0;
    151     for(int i=0;i<m;i++)
    152     if(iscut[0][EDGENODE(i)] || iscut[1][EDGENODE(i)])
    153     cnt++;
    154     
    155     printf("%d\n",cnt);
    156     
    157     for(int i=0;i<m;i++)
    158     if(iscut[0][EDGENODE(i)] || iscut[1][EDGENODE(i)])
    159     printf("%d\n",i+1);
    160     
    161     
    162     return 0;
    163 }
    View Code

    关于无向图的搜索树和dfs序

     如何快速判断一个无向图中,删掉一个点后,它的邻点的连通情况?

    求出DFS序以后,在搜索树上做判断: 假设两个邻点为a,b.删掉的点为c.

    那么a在c引领的子树内的充要条件为 dfn(c)<=dfn(a) 并且 dfn(a)<dfn(c)+SizeofSubTree(c).

    用这个判断: 1.a,b分立在c的两个子树内. 那么a,b连通的条件是 low[a]<=dfn(c) 并且 low[b]<=dfn(c).

    2.c在a到b的路径上. a,b连通的条件是 low[a]<=dfn(c). (假设a在c的子树内,b不在.注意无向图没有横叉边.)

    其它所有情况一定都是连通的.

     

    已完结

    有向图割点 & 有向图割边 <-这俩是啥

     

  • 相关阅读:
    神兽保佑-代码无BUG
    HDU 1022 Train Problem I (数据结构 —— 栈)
    iOS开发
    漫谈程序猿系列:无BUG不生活
    王立平--Unity破解
    java远程调用rmi入门实例
    高仿美团iOS版,版本5.7
    JAVA日志系统
    读《互联网创业password》之随想
    解决iOS空指针数据的问题
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4295943.html
Copyright © 2011-2022 走看看