求割边割点
对于一个连通图,删去某个点(删去一个点即把该点和与该点相邻接的边都删去)的集合得到的图将不再连通,删去该集合的任意子集该图依然连通,则称其为该图的一个点割集,若该集合只有一个点组成,则称其为割点。
同样对于一个连通图删去某个边的集合(删去一条边仅删去该条边即可)得到的图将不再连通,删去该边集合的任意子集该图依然连通,则称其为该图的边割集,若该集合只有一条边组成,则称其为割边即桥。
求割边割点最直接的方法就是按照定义,删去点或边然后对图进行遍历,看是否仍连通,但要求一个图的割点割边对整个图的每个点和每条边都需要做一下试探,时间复杂度太高。
求割边割点的过程,以某一个点开始做dfs,采用数组low[i],dep[i]表示一个节点可以到达的除其父亲外的最早被访问的点,dep表示该点的深度。
若有节点u有子节点v,且low[v]>=dep[u]则点u是割点。
若有low[v]>dep[u]则边(u,v)为割边.
 1 int low[MAX],dep[MAX],mark[MAX],cutpoint[MAX];
int low[MAX],dep[MAX],mark[MAX],cutpoint[MAX];
 2 void dfs(int s,int father,int depth)
void dfs(int s,int father,int depth)
 3

 {
{
 4 int u,v,tot=0;
   int u,v,tot=0;
 5 mark[s]=1;
   mark[s]=1;
 6 low[s]=dep[s]=depth;
   low[s]=dep[s]=depth;
 7 for(int i=0;i<mp[s].size();i++)
   for(int i=0;i<mp[s].size();i++)
 8
 
    {
{
 9 v=mp[s][i];
      v=mp[s][i];
10 if(mark[v]==1&&v!=father&&dep[v]<low[s])
      if(mark[v]==1&&v!=father&&dep[v]<low[s])
11 low[s]=dep[v];
      low[s]=dep[v];
12 else if(mark[v]==0)
      else if(mark[v]==0) 
13
 
       {
{
14 tot++;
         tot++;
15 dfs(v,s,depth+1)
         dfs(v,s,depth+1)
16 if(low[v]<low[s])
         if(low[v]<low[s])
17 low[s]=low[v];
         low[s]=low[v];
18 if((s==root&&tot>1)||(s!=root&&low[v]>=dep[s]))
         if((s==root&&tot>1)||(s!=root&&low[v]>=dep[s]))
19 cutpoint[s]=1;
         cutpoint[s]=1;
20 if(low[v]>dep[s])
         if(low[v]>dep[s])
21 //标记边(s,v)为割边
         //标记边(s,v)为割边 
22 }
      }
23 }
   }
24 mark[s]=2;
   mark[s]=2;
25 }
}
26
27