zoukankan      html  css  js  c++  java
  • 专题训练之双连通

    桥和割点例题+讲解:hihocoder1183 http://hihocoder.com/problemset/problem/1183

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<set>
      6 using namespace std;
      7 const int maxn=1005;
      8 const int maxm=200010;
      9 struct edge{
     10     int to,nxt;
     11     bool cut;
     12 }edge[maxm*2];
     13 int head[maxn],tot;
     14 int low[maxn],dfn[maxn];
     15 int index,n,bridge;
     16 set<int>st;
     17 bool cut[maxn];
     18 
     19 void addedge(int u,int v)
     20 {
     21     edge[tot].to=v;
     22     edge[tot].nxt=head[u];
     23     edge[tot].cut=false;
     24     head[u]=tot++;
     25 }
     26 
     27 void tarjan(int u,int pre)
     28 {
     29     low[u]=dfn[u]=++index;
     30     int son=0;
     31     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
     32         int v=edge[i].to;
     33         if ( v==pre ) continue;
     34         if ( !dfn[v] ) {
     35             son++;
     36             tarjan(v,u);
     37             low[u]=min(low[u],low[v]);
     38             if ( low[v]>dfn[u] ) {
     39                 bridge++;
     40                 edge[i].cut=true;
     41                 edge[i^1].cut=true;
     42             }
     43             if ( low[v]>=dfn[u] && u!=pre ) {
     44                 st.insert(u);
     45                 cut[u]=true;
     46             }
     47         }
     48         else if ( low[u]>dfn[v] ) low[u]=dfn[v];
     49     }
     50     if ( u==pre && son>1 ) {
     51         cut[u]=true;
     52         st.insert(u);
     53     }
     54 }
     55 
     56 void solve()
     57 {
     58     memset(low,0,sizeof(low));
     59     memset(dfn,0,sizeof(dfn));
     60     memset(cut,false,sizeof(cut));
     61     index=bridge=0;
     62     st.clear();
     63     for ( int i=1;i<=n;i++ ) {
     64         if ( !dfn[i] ) tarjan(i,i);
     65     }
     66     set<int>::iterator it;
     67     if ( st.size()==0 ) printf("Null
    ");
     68     else {
     69         for ( it=st.begin();it!=st.end();it++ ) {
     70             if ( it!=st.begin() ) printf(" ");
     71             printf("%d",*it);
     72         }
     73         printf("
    ");
     74     }
     75     vector<pair<int,int> >ans;
     76     for ( int i=1;i<=n;i++ ) {
     77         for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
     78             if ( edge[j].cut && edge[j].to>i ) ans.push_back(make_pair(i,edge[j].to));
     79         }
     80     }
     81     sort(ans.begin(),ans.end());
     82     for ( int i=0;i<ans.size();i++ ) {
     83         printf("%d %d
    ",ans[i].first,ans[i].second);
     84     }
     85 }
     86 
     87 void init()
     88 {
     89     tot=0;
     90     memset(head,-1,sizeof(head));
     91 }
     92 
     93 int main()
     94 {
     95     int m,i,j,k,x,y,z;
     96     while ( scanf("%d%d",&n,&m)!=EOF ) {
     97         init();
     98         while ( m-- ) {
     99             scanf("%d%d",&x,&y);
    100             addedge(x,y);
    101             addedge(y,x);
    102         }
    103         solve();
    104     }
    105 }
    桥和割点模板

    边双连通模板

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 using namespace std;
     6 const int maxn=1005;
     7 const int maxm=200010;
     8 struct edge{
     9     int to,nxt;
    10     bool cut;
    11 }edge[maxm*2];
    12 int head[maxn],tot,n;
    13 int index,ebc_cnt,bridge;
    14 int dfn[maxn],low[maxn];
    15 
    16 void addedge(int u,int v)
    17 {
    18     edge[tot].to=v;
    19     edge[tot].nxt=head[u];
    20     edge[tot].cut=false;
    21     head[u]=tot++;
    22 }
    23 
    24 void tarjan(int u,int pre)
    25 {
    26     low[u]=dfn[u]=++index;
    27     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
    28         int v=edge[i].to;
    29         if ( v==pre ) continue;
    30         if ( !dfn[v] ) {
    31             tarjan(v,u);
    32             low[u]=min(low[u],low[v]);
    33             if ( low[v]>dfn[u] ) {
    34                 bridge++;
    35                 edge[i].cut=true;
    36                 edge[i^1].cut=true;
    37             }
    38         }
    39         else if ( low[u]>dfn[v] ) low[u]=dfn[v];
    40     }
    41 }
    42 
    43 void solve()
    44 {
    45     memset(low,0,sizeof(low));
    46     memset(dfn,0,sizeof(dfn));
    47     index=bridge=0;
    48     for ( int i=1;i<=n;i++ ) {
    49         if ( !dfn[i] ) tarjan(i,i);
    50     }
    51 }
    52 
    53 void init()
    54 {
    55     tot=0;
    56     memset(head,-1,sizeof(head));
    57 }
    边双连通模板

    点双连通模板

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<stack>
     5 #include<vector> 
     6 using namespace std;
     7 const int maxn=1005;
     8 const int maxm=200010;
     9 struct edge{
    10     int to,nxt;
    11 }edge[maxm*2];
    12 struct Edge{
    13     int u,v;
    14     Edge(int _u=0,int _v=0):u(_u),v(_v) {}
    15 };
    16 int dfn[maxn],low[maxn];
    17 int head[maxn],tot;
    18 int index,n;
    19 bool cut[maxn];
    20 int bcc_cnt,bccno[maxn];
    21 vector<int>bcc[maxn];
    22 stack<Edge>s;
    23 
    24 void addedge(int u,int v)
    25 {
    26     edge[tot].to=v;
    27     edge[tot].nxt=head[u];
    28     head[u]=tot++;
    29 }
    30 
    31 void tarjan(int u,int pre)
    32 {
    33     low[u]=dfn[u]=++index;
    34     int son=0;
    35     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
    36         int v=edge[i].to;
    37         if ( v==pre ) continue;
    38         Edge e(u,v);
    39         if ( !dfn[v] ) {
    40             s.push(e);
    41             son++;
    42             tarjan(v,u);
    43             low[u]=min(low[u],low[v]);
    44             if ( low[v]>=dfn[u] ) {
    45                 cut[u]=true;
    46                 bcc_cnt++;
    47                 bcc[bcc_cnt].clear();
    48                 for (;;)
    49                 {
    50                     Edge x=s.top();
    51                     s.pop();
    52                     if ( bccno[x.u]!=bcc_cnt ) {
    53                         bcc[bcc_cnt].push_back(x.u);
    54                         bccno[x.u]=bcc_cnt;
    55                     }
    56                     if ( bccno[x.v]!=bcc_cnt ) {
    57                         bcc[bcc_cnt].push_back(x.v);
    58                         bccno[x.v]=bcc_cnt;
    59                     }
    60                     if ( x.u==u && x.v==v ) break;
    61                 }
    62             }
    63         }
    64         else if ( dfn[v]<dfn[u] && v!=pre ) {
    65             s.push(e);
    66             low[u]=min(low[u],dfn[v]);
    67         }
    68     }
    69     if ( u==pre && son==1 ) cut[u]=false;
    70 }
    71 
    72 void solve()
    73 {
    74     memset(dfn,0,sizeof(dfn));
    75     memset(low,0,sizeof(low));
    76     memset(cut,false,sizeof(cut));
    77     index=bcc_cnt=0;
    78     while ( !s.empty() ) s.pop();
    79     for ( int i=1;i<=n;i++ ) {
    80         if ( !dfn[i] ) tarjan(i,i);
    81     }
    82 }
    83 
    84 void init()
    85 {
    86     tot=0;
    87     memset(head,-1,sizeof(head));
    88 }
    点双连通模板

    1.(POJ2117)http://poj.org/problem?id=2117 (求连通块数量)

    题意:去掉一个点使得有更多的连通块,求最多有多少连通块

    分析:添加数组add_block[],当u为割点时则add_block[u]++,最后逐一枚举要去掉的点。特别注意对于数根来说add_block[u]=son-1

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 #include<set>
     6 using namespace std;
     7 const int maxn=20005;
     8 const int maxm=100010;
     9 struct edge{
    10     int to,nxt;
    11     bool cut;
    12 }edge[maxm*3];
    13 int head[maxn],tot;
    14 int low[maxn],dfn[maxn];
    15 int index,n,bridge;
    16 int add_block[maxn];
    17 set<int>st;
    18 bool cut[maxn];
    19 
    20 void addedge(int u,int v)
    21 {
    22     edge[tot].to=v;
    23     edge[tot].nxt=head[u];
    24     edge[tot].cut=false;
    25     head[u]=tot++;
    26 }
    27 
    28 void tarjan(int u,int pre)
    29 {
    30     low[u]=dfn[u]=++index;
    31     int son=0;
    32     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
    33         int v=edge[i].to;
    34         if ( v==pre ) continue;
    35         if ( !dfn[v] ) {
    36             son++;
    37             tarjan(v,u);
    38             low[u]=min(low[u],low[v]);
    39             if ( low[v]>dfn[u] ) {
    40                 bridge++;
    41                 edge[i].cut=true;
    42                 edge[i^1].cut=true;
    43             }
    44             if ( u!=pre && low[v]>=dfn[u] ) {
    45                 st.insert(u);
    46                 cut[u]=true;
    47                 add_block[u]++;
    48             }
    49         }
    50         else if ( low[u]>dfn[v] ) low[u]=dfn[v];
    51     }
    52     if ( u==pre && son>1 ) {
    53         cut[u]=true;
    54         st.insert(u);
    55     }
    56     if ( u==pre ) add_block[u]=son-1;
    57 }
    58 
    59 void solve()
    60 {
    61     memset(low,0,sizeof(low));
    62     memset(dfn,0,sizeof(dfn));
    63     memset(cut,false,sizeof(cut));
    64     memset(add_block,0,sizeof(add_block));
    65     int cnt,ans;
    66     index=bridge=cnt=ans=0;
    67     for ( int i=1;i<=n;i++ ) {
    68         if ( !dfn[i] ) {
    69             tarjan(i,i);
    70             cnt++;
    71         }
    72     }
    73     for ( int i=1;i<=n;i++ ) ans=max(ans,cnt+add_block[i]);
    74     printf("%d
    ",ans);
    75 }
    76 
    77 void init()
    78 {
    79     tot=0;
    80     memset(head,-1,sizeof(head));
    81     st.clear();
    82 }
    83 
    84 int main()
    85 {
    86     int m,i,j,k,x,y,z;
    87     while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) {
    88         init();
    89         while ( m-- ) {
    90             scanf("%d%d",&x,&y);
    91             x++;y++;
    92             addedge(x,y);
    93             addedge(y,x);
    94         }
    95         solve();
    96     }
    97 }
    POJ2117

    2.(POJ3117)http://poj.org/problem?id=3177 (构造边双连通)

    题意:求添加多少条边后在图中的任意两点都有两条边不重复的路径

    分析:边双连通,利用强连通分量中的写法,把每个点对应的缩点后的点标记下来。最后构建新图(即进行缩点,边只存在原先为桥的边)记录入度(或者出度,选择一个即可),最后入度为1的点即为叶子节点,对于一棵树想要使其变成边双连通,所加的边数=(叶子节点的个数+1)/2

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 using namespace std;
      6 const int maxn=1005;
      7 const int maxm=200010;
      8 struct edge{
      9     int to,nxt;
     10     bool cut;
     11 }edge[maxm*2];
     12 int head[maxn],tot,n;
     13 int index,ebc_cnt,bridge,block,top;
     14 int dfn[maxn],low[maxn],belong[maxn],stack[maxn],du[maxn];
     15 bool vis[maxn];
     16 
     17 void addedge(int u,int v)
     18 {
     19     edge[tot].to=v;
     20     edge[tot].nxt=head[u];
     21     edge[tot].cut=false;
     22     head[u]=tot++;
     23 }
     24 
     25 void tarjan(int u,int pre)
     26 {
     27     low[u]=dfn[u]=++index;
     28     stack[top++]=u;
     29     vis[u]=true;
     30     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
     31         int v=edge[i].to;
     32         if ( v==pre ) continue;
     33         if ( !dfn[v] ) {
     34             tarjan(v,u);
     35             low[u]=min(low[u],low[v]);
     36             if ( low[v]>dfn[u] ) {
     37                 bridge++;
     38                 edge[i].cut=true;
     39                 edge[i^1].cut=true;
     40             }
     41         }
     42         else if ( low[u]>dfn[v] && vis[v] ) low[u]=dfn[v];
     43     }
     44     if ( low[u]==dfn[u] ) {
     45         block++;
     46         int v;
     47         do
     48         {
     49             v=stack[--top];
     50             vis[v]=true;
     51             belong[v]=block;
     52         }
     53         while ( v!=u );
     54     }
     55 }
     56 
     57 void solve()
     58 {
     59     memset(low,0,sizeof(low));
     60     memset(dfn,0,sizeof(dfn));
     61     memset(vis,false,sizeof(vis));
     62     index=bridge=block=top=0;
     63     for ( int i=1;i<=n;i++ ) {
     64         if ( !dfn[i] ) tarjan(i,i);
     65     }
     66     memset(du,0,sizeof(du));
     67     for ( int i=1;i<=n;i++ ) {
     68         for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
     69             if ( edge[j].cut ) {
     70                 du[belong[i]]++;
     71             }
     72         }
     73     }
     74     int cnt=0;
     75     for ( int i=1;i<=block;i++ ) {
     76         if ( du[i]==1 ) cnt++;
     77     }
     78     printf("%d
    ",(cnt+1)/2);
     79 }
     80 
     81 void init()
     82 {
     83     tot=0;
     84     memset(head,-1,sizeof(head));
     85 }
     86 
     87 int main()
     88 {
     89     int m,i,j,k,x,y,z;
     90     while ( scanf("%d%d",&n,&m)!=EOF ) {
     91         init();
     92         for ( i=1;i<=m;i++ ) {
     93             scanf("%d%d",&x,&y);
     94             addedge(x,y);
     95             addedge(y,x);
     96         }
     97         solve();
     98     }
     99     return 0;
    100 }
    POJ3117

    3.(HDOJ2242)http://acm.hdu.edu.cn/showproblem.php?pid=2242

    分析:边双连通+搜索。首先分成3类情况,对于初始时连通块的数量>2或者连通块为1但不存在桥直接输出impossible。而对于连通块本身为2的图来说不用切断如何一条管道即可将整个图分成两部分。最后仅仅需要对连通块数量为1,同时桥的数量>0的图进行考虑即可。给每个点标号标记它们属于第几个边强连通分量,然后构建新图。最后对新图进行搜索,不断更新答案.同时注意存在重flag解决存在重边的问题。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<cmath>
      6 using namespace std;
      7 const int maxn=10005;
      8 const int maxm=20010;
      9 struct edge{
     10     int to,nxt;
     11     bool cut;
     12 }edge[maxm*2];
     13 int head[maxn],tot,n;
     14 int index,ebc_cnt,bridge,block,top,ans,sum;
     15 int dfn[maxn],low[maxn],belong[maxn],stack[maxn],num[maxn],num_[maxn];
     16 bool vis[maxn];
     17 vector<int>G[maxn];
     18 
     19 void addedge(int u,int v)
     20 {
     21     edge[tot].to=v;
     22     edge[tot].nxt=head[u];
     23     edge[tot].cut=false;
     24     head[u]=tot++;
     25 }
     26 
     27 void addedge_(int u,int v)
     28 {
     29     G[u].push_back(v);
     30 }
     31 
     32 void tarjan(int u,int pre)
     33 {
     34     low[u]=dfn[u]=++index;
     35     stack[top++]=u;
     36     vis[u]=true;
     37     bool flag=false;
     38     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
     39         int v=edge[i].to;
     40         if ( v==pre && !flag ) {
     41             flag=true;
     42             continue;
     43         }
     44         if ( !dfn[v] ) {
     45             tarjan(v,u);
     46             low[u]=min(low[u],low[v]);
     47             if ( low[v]>dfn[u] ) {
     48                 bridge++;
     49                 edge[i].cut=true;
     50                 edge[i^1].cut=true;
     51             }
     52         }
     53         else if ( low[u]>dfn[v] && vis[v] ) low[u]=dfn[v];
     54     }
     55     if ( low[u]==dfn[u] ) {
     56         block++;
     57         int v;
     58         do
     59         {
     60             v=stack[--top];
     61             vis[v]=true;
     62             belong[v]=block;
     63         }
     64         while ( v!=u );
     65     }
     66 }
     67 
     68 int dfs(int u,int pre)
     69 {
     70     int now=num_[u];
     71     for ( int i=0;i<G[u].size();i++ ) {
     72         int v=G[u][i];
     73         if ( v!=pre ) now+=dfs(v,u);
     74     }
     75     ans=min(ans,abs(sum-2*now));
     76     return now;
     77 }
     78 
     79 void solve()
     80 {
     81     memset(low,0,sizeof(low));
     82     memset(dfn,0,sizeof(dfn));
     83     memset(vis,false,sizeof(vis));
     84     int cnt,now;
     85     index=bridge=block=top=now=cnt=0;
     86     for ( int i=1;i<=n;i++ ) {
     87         if ( !dfn[i] ) {
     88             tarjan(i,i);
     89             cnt++;
     90         }
     91         if ( i==1 ) {
     92             for ( int j=1;j<=n;j++ ) {
     93                 if ( dfn[j] ) now+=num[j];
     94             }
     95         }
     96     }
     97     memset(num_,0,sizeof(num_));
     98     for ( int i=1;i<=n;i++ ) num_[belong[i]]+=num[i];
     99     if ( cnt>2 || bridge==0 ) {
    100         printf("impossible
    ");
    101         return;
    102     }
    103     else if ( cnt==2 ) {
    104         printf("%d
    ",abs(sum-2*now));
    105         return;
    106     }
    107     for ( int i=1;i<=block;i++ ) G[i].clear();
    108     for ( int i=1;i<=n;i++ ) {
    109         for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
    110             int v=edge[j].to;
    111             if ( edge[j].cut ) {
    112                 int x=belong[i];
    113                 int y=belong[v];
    114                 addedge_(x,y);
    115             }
    116         }
    117     }
    118     ans=sum;
    119     dfs(1,1);
    120     printf("%d
    ",ans);
    121 }
    122 
    123 void init()
    124 {
    125     tot=0;
    126     memset(head,-1,sizeof(head));
    127 }
    128 
    129 int main()
    130 {
    131     int m,i,j,k,x,y,z;
    132     while ( scanf("%d%d",&n,&m)!=EOF ) {
    133         init();
    134         sum=0;
    135         for ( i=1;i<=n;i++ ) {
    136             scanf("%d",&num[i]);
    137             sum+=num[i];
    138         }
    139         for ( i=1;i<=m;i++ ) {
    140             scanf("%d%d",&x,&y);
    141             x++;y++;
    142             addedge(x,y);
    143             addedge(y,x);
    144         }
    145         solve();
    146     }
    147     return 0;
    148 }
    HDOJ2242
  • 相关阅读:
    ivew-admin 导入excel
    ivew Upload 上传时附带的额外参数
    工厂方法模式
    简单工厂模式
    webpack (1)
    商品格子
    合同签名
    展示图片数组
    使用egg.js和egg-sequelize连接mysql
    egg 连接mysql 在mysql 插入数据
  • 原文地址:https://www.cnblogs.com/HDUjackyan/p/8822773.html
Copyright © 2011-2022 走看看