割点割边连通分量等连通性相关算法

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不在.注意无向图没有横叉边.)

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

 

已完结

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

 

posted @ 2015-02-18 17:45  DragoonKiller  阅读(368)  评论(0编辑  收藏  举报