专题训练之双连通

桥和割点例题+讲解: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\n");
 68     else {
 69         for ( it=st.begin();it!=st.end();it++ ) {
 70             if ( it!=st.begin() ) printf(" ");
 71             printf("%d",*it);
 72         }
 73         printf("\n");
 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\n",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.(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\n",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\n",(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

原文地址:https://www.cnblogs.com/HDUjackyan/p/8822773.html

时间: 2024-11-03 23:25:36

专题训练之双连通的相关文章

HDU 4005 The war(双连通好题)

HDU 4005 The war 题目链接 题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通 思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可 代码:

ACM学习-图双连通子图

// ACM学习-割点和桥.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<queue> #include<vector> #include<algorithm> using namespace std; const int v = 13; int edge[v][v] = { { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0

双连通问题

一些定义: 割点集合(割集):在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 点连通度:最小割点集合中的顶点数. 割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 边连通度:最小割边集合中的边数. 点双连通:如果一个无向连通图的点连通度大于1,则称该图是点双连通的,简称双连通或重连通.割点:一个图有割点,当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为

图的连通性问题的小结 (双连通、2-SAT)

图的连通性问题包括: 1.强连通分量. 2.最小点基和最小权点基. 3.双连通. 4.全局最小割. 5.2-SAT 一.强连通分量 强连通分量很少单独出题,一般都是把求强连通分量作为缩点工具. 有三种算法: 1.Kosaraju算法.对原图和反图分别进行一次深度优先搜索. 2.Tarjan算法.用了时间戳. 3.Garbow算法.与Tarjan算法是同一思想,但更精妙. 三种算法的模版我已经贴过了  http://www.cnblogs.com/Potato-lover/p/3956604.ht

poj1515--Street Directions(边的双连通)

给一个无向图,要求变成强连通的有向图,需要保留哪些边. 边的双连通,对于桥保留两条边,其他的只保留一条边.求双连通的过程中记录保留边. /********************************************* Problem: 1515 User: G_lory Memory: 232K Time: 32MS Language: C++ Result: Accepted **********************************************/ #incl

【图论】双连通总结

双连通总结 这类问题分为,边-双连通,点-双连通 边双连通 边双连通,求出来后,连接没一个双连通的分量的就是割边,因此可以缩点成一棵树,把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通 基本这类题都一个解法,求双连通分量,然后缩点成树,进行操作 或者就是直接要求割边,做跟割边相关的操作 模板: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #

poj3352Road Construction 边双连通+伪缩点

/* 对于边双连通分支,求法更为简单.只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分支.桥不属于任何 一个边双连通分支,其余的边和每个顶点都属于且只属于一个边双连通分支. 一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥, 然后删除这些桥边,剩下的每个连通块都是一个双连通子图.把每个双连通子图收缩为一个顶点, 再把桥边加回来,最后的这个图一定是一棵树,边连通度为1. 统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf.则

割点、桥模板以及点双连通、边双连通

一.概念 概念: 1.桥: 如果在图G中删去一条边e后,图G的连通分支数增加,即W(G-e)>W(G),则称边u为G的桥,又称割边或关节边. 2.割点:如果在图G中删去一个结点u后,图G的连通分枝数增加,即W(G-u)>W(G),则称结点u为G的割点,又称关节点. 3.点双连通分量:不含割点的连通子图 4.边双连通分量:不含割边的连通子图 性质: 1.边双连通分量中,任意两点都在某个边环中.(任意两点不一定在点环中) 2.点双连通分量中,任意两点都在某个点环中. 3.点双连通分量不一定是边双连

poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&amp;&amp;缩点】

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10141   Accepted: 5031 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the r