zoukankan      html  css  js  c++  java
  • DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)

    一、dfs框架:

     1 vector<int>G[maxn];  //存图
     2 int vis[maxn];      //节点访问标记
     3 void dfs(int u)
     4 {
     5     vis[u] = 1;
     6     PREVISIT(u);    //访问节点u之前的操作
     7     int d = G[u].size();
     8     for(int i = 0; i < d; i++)//枚举每条边
     9     {
    10         int v = G[u][i];
    11         if(!vis[v])dfs(v);
    12     }
    13     POSTVISIT(u);   //访问节点u之后的操作
    14 }

    二、无向图连通分量

     1 void find_cc()
     2 {
     3     current_cc = 0;//全局变量 连通块编号
     4     memset(vis, 0, sizeof(vis));
     5     for(int u = 0; u < n; u++)if(!vis[u])//依次检查每个节点,如果未访问过,说明它属于一个新的连通分量,从该点dfs访问整个连通分量
     6     {
     7         current_cc++;
     8         dfs(u);
     9     }
    10 }

    三、二分图判定

    调用之前,清空color数组,调用之前,先给color[u]赋值1

     1 int color[maxn];//0表示未染色 1表示白色 2表示黑色
     2 bool bipartite(int u)
     3 {
     4     for(int i = 0; i < G[u].size(); i++)
     5     {
     6         int v = G[u][i];
     7         if(color[u] == color[v])return false;//u v颜色一样
     8         if(!color[v])
     9         {
    10             color[v] = 3 - color[u];//节点u与v染不同的颜色
    11             if(!bipartite(v))return false;
    12         }
    13     }
    14     return true;
    15 }

    四、无向图的割点和桥

    加入时间戳

    int dfs_clock;
    void PREVISIT(int u){pre[u] = ++dfs_clock;}
    void POSTVISIT(int u){post[u] = ++dfs_clock;}

     注意:求桥的时候注意重边

    求割点和桥可以用下面求双连通分量的代码

    五、无向图的双连通分量

    点-双连通分量

     1 struct Edge
     2 {
     3     int u, v;
     4     Edge(){}
     5     Edge(int u, int v):u(u), v(v){}
     6 };
     7 int pre[maxn];//时间戳数组
     8 int iscut[maxn];//割点
     9 int bccno[maxn];//点-双连通分量编号 (割点的编号没有意义)
    10 int dfs_clock, bcc_cnt;//时间戳 双连通分量编号
    11 vector<int>G[maxn], bcc[maxn];//G存储图 bcc存储每个双连通分量的点
    12 stack<Edge>S;
    13 
    14 int dfs(int u, int fa)
    15 {
    16     int lowu = pre[u] = ++dfs_clock;
    17     int child = 0;
    18     for(int i = 0; i < G[u].size(); i++)
    19     {
    20         int v = G[u][i];
    21         Edge e(u, v);
    22         if(!pre[v])
    23         {
    24             S.push(e);
    25             child++;
    26             int lowv = dfs(v, u);
    27             lowu = Min(lowu, lowv);
    28             if(lowv >= pre[u])
    29             {
    30                 iscut[u] = 1;
    31                 bcc_cnt++;
    32                 bcc[bcc_cnt].clear();
    33                 for(;;)
    34                 {
    35                     Edge x = S.top();
    36                     S.pop();
    37                     if(bccno[x.u] != bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u] = bcc_cnt;}
    38                     if(bccno[x.v] != bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v] = bcc_cnt;}
    39                     if(x.u == u && x.v == v)break;
    40                 }
    41             }
    42         }
    43         else if(pre[v] < pre[u] && v != fa)
    44         {
    45             S.push(e);
    46             lowu = Min(lowu, pre[v]);
    47         }
    48     }
    49     if(fa < 0 && child == 1)iscut[u] = 0;
    50     return lowu;
    51 }
    52 void find_bcc(int n)//求解点-双连通分量
    53 {
    54     Mem(pre);
    55     Mem(iscut);
    56     Mem(bccno);
    57     dfs_clock = bcc_cnt = 0;
    58     for(int i = 0; i < n; i++)if(!pre[i])dfs(i, -1);
    59 }

     边-双连通分量

     1 struct Edge
     2 {
     3     int u, v;
     4     Edge(){}
     5     Edge(int u, int v):u(u), v(v){}
     6 };
     7 int pre[maxn];//时间戳数组
     8 int isbridge[maxm];//
     9 int bccno[maxn];//边-双连通分量编号 (任意两个无交集)
    10 int low[maxn];//low[u]为u后代可以返回的最早祖先值
    11 int dfs_clock, bcc_cnt;//时间戳 双连通分量编号
    12 vector<Edge>e;//存边
    13 vector<int>G[maxn], bcc[maxn];//G存储图 bcc存储每个双连通分量的点
    14 //G存边在e中的下标
    15 void init(int n)
    16 {
    17     for(int i = 0; i < n; i++)G[i].clear();
    18     e.clear();
    19 }
    20 void addedge(int u, int v)//双向边
    21 {
    22     e.push_back(Edge(u, v));
    23     G[u].push_back(e.size() - 1);
    24     e.push_back(Edge(v, u));
    25     G[v].push_back(e.size() - 1);//正好满足双向边^操作
    26 }
    27 void dfs1(int u, int fa)//找出所有的桥
    28 {
    29     low[u] = pre[u] = ++dfs_clock;
    30     for(int i = 0; i < G[u].size(); i++)
    31     {
    32         int v = e[G[u][i]].v;
    33         if(!pre[v])
    34         {
    35             dfs1(v, u);
    36             low[u] = Min(low[u], low[v]);
    37             if(low[v] > pre[u])//是桥,双向边均标记一下
    38             {
    39                 isbridge[G[u][i]] = isbridge[G[u][i]^1] = 1;
    40             }
    41         }
    42         else if(pre[v] < pre[u] && v != fa)
    43         {
    44             low[u] = Min(low[u], pre[v]);
    45         }
    46     }
    47 }
    48 void dfs2(int u)//dfs染色找边-双连通分量即可
    49 {
    50     pre[u] = 1;//vis数组标记
    51     bccno[u] = bcc_cnt;
    52     bcc[bcc_cnt].push_back(u);
    53     for(int i = 0; i < G[u].size(); i++)
    54     {
    55         int v = e[G[u][i]].v;
    56         if(isbridge[G[u][i]])continue;//不走桥
    57         if(!pre[v])dfs2(v);
    58     }
    59 }
    60 void find_bcc(int n)//求解边-双连通分量
    61 {
    62     Mem(pre);Mem(isbridge);Mem(bccno);Mem(low);
    63     dfs_clock = bcc_cnt = 0;
    64     for(int i = 0; i < n; i++)if(!pre[i])dfs1(i, -1);
    65     Mem(pre);
    66     for(int i = 0; i < n; i++)if(!pre[i]){bcc_cnt++; bcc[bcc_cnt].clear(); dfs2(i);}
    67 }

    六、有向图的强连通分量

     1 vector<int>G[maxn];
     2 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
     3 stack<int>S;
     4 void dfs(int u)
     5 {
     6     pre[u] = lowlink[u] = ++dfs_clock;
     7     S.push(u);
     8     for(int i = 0; i < G[u].size(); i++)
     9     {
    10         int v = G[u][i];
    11         if(!pre[v])
    12         {
    13             dfs(v);
    14             lowlink[u] = Min(lowlink[u], lowlink[v]);
    15         }
    16         else if(!sccno[v])
    17         {
    18             lowlink[u] = Min(lowlink[u], pre[v]);
    19         }
    20     }
    21     if(lowlink[u] == pre[u])
    22     {
    23         scc_cnt++;
    24         for(;;)
    25         {
    26             int x = S.top();
    27             S.pop();
    28             sccno[x] = scc_cnt;
    29             if(x == u)break;
    30         }
    31     }
    32 }
    33 void find_scc(int n)
    34 {
    35     dfs_clock = scc_cnt = 0;
    36     Mem(sccno);
    37     Mem(pre);
    38     for(int i = 0; i < n; i++)if(!pre[i])dfs(i);
    39 }

    七、2-SAT问题

     1 struct TwoSAT
     2 {
     3     int n;
     4     vector<int>G[maxn * 2];
     5     bool mark[maxn * 2];
     6     int S[maxn * 2], c;
     7     bool dfs(int x)
     8     {
     9         if(mark[x^1])return false;
    10         if(mark[x])return true;
    11         mark[x] = true;
    12         S[c++] = x;
    13         for(int i = 0; i < G[x].size(); i++)
    14             if(!dfs(G[x][i]))return false;
    15         return true;
    16     }
    17     void init(int n)
    18     {
    19         this->n = n;
    20         for(int i = 0; i < n * 2; i++)G[i].clear();
    21         Mem(mark);
    22     }
    23     //x = xval or y = yval
    24     void add_clause(int x, int xval, int y, int yval)
    25     {
    26         x = x * 2 + xval;
    27         y = y * 2 + yval;
    28         G[x ^ 1].push_back(y);
    29         G[y ^ 1].push_back(x);
    30     }
    31     bool solve()
    32     {
    33         for(int i = 0; i < n * 2; i += 2)
    34         {
    35             if(!mark[i] && !mark[i + 1])
    36             {
    37                 c = 0;
    38                 if(!dfs(i))
    39                 {
    40                     while(c > 0)mark[S[--c]] = false;
    41                     if(!dfs(i + 1))return false;
    42                 }
    43             }
    44         }
    45         return true;
    46     }
    47 };
  • 相关阅读:
    通过Logstash由SQLServer向Elasticsearch同步数据
    ELK +Nlog 分布式日志系统的搭建 For Windows
    Gulp 给所有静态文件引用加版本号
    Fluentdata详解
    jQuery Easy UI (适应屏幕分辨率大小)布局(Layout)
    什么是数据结构---算法
    WCF的学习之旅
    程序员必学之精华----软件工程
    译 .NET Core 3.0 发布
    Vue+Element UI 实现视频上传
  • 原文地址:https://www.cnblogs.com/fzl194/p/9580306.html
Copyright © 2011-2022 走看看