双联通分量复习

1,边双联通(桥)

POJ3177Redundant Paths

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 17989   Accepted: 7470

Description

In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forced to take a particular path and want to build some new paths so that they will always have a choice of at least two separate routes between any pair of fields. They currently have at least one route between each pair of fields and want to have at least two. Of course, they can only travel on Official Paths when they move from one field to another.

Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way.

There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.

Input

Line 1: Two space-separated integers: F and R

Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.

Output

Line 1: A single integer that is the number of new paths that must be built.

Sample Input

7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

Sample Output

2

Hint

Explanation of the sample:

One visualization of the paths is:

   1   2   3   +---+---+         |   |       |   | 6 +---+---+ 4      / 5     /     /  7 +

Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions.

   1   2   3   +---+---+     :   |   |   :   |   | 6 +---+---+ 4      / 5  :     /     :    /      : 7 + - - - - 

Check some of the routes: 
1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2 
1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4 
3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7 
Every pair of fields is, in fact, connected by two routes.

It‘s possible that adding some other path will also solve the problem (like one from 6 to 7). Adding two paths, however, is the minimum.

  1 /**
  2 在树中至少添加多少条边能使图变为双连通图。
  3 结论:添加边数=(树中度为1的节点数+1)/2
  4
  5 具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,
  6 这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的
  7 环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样
  8 一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。
  9
 10 */
 11 #include <cstdio>
 12 #include <iostream>
 13 #include <cstring>
 14 #include <algorithm>
 15 #include <cmath>
 16 #include <stack>
 17
 18 using namespace std;
 19 const int MAXN = 5e3 + 7;
 20 const int MAXM = 1e4 + 7;
 21
 22 struct Edge {
 23     int to, w, next;
 24     int cut;
 25 } edge[MAXM * 2];
 26
 27 int first[MAXN], dfn[MAXN], low[MAXN], belong[MAXN], degree[MAXN], ins[MAXM];
 28
 29 stack<int>st;
 30
 31 int bridge; ///桥的数目
 32
 33 int sign, n, m;
 34
 35 int indx, scc;
 36
 37 inline void init() {
 38     memset(first, -1, sizeof(first));
 39     sign = 0;
 40 }
 41
 42 inline void add_edge(int u, int v, int w) {
 43     edge[sign].to = v;
 44     edge[sign].w = w;
 45     edge[sign].cut = 0;
 46     edge[sign].next = first[u];
 47     first[u] = sign++;
 48 }
 49
 50 void tarjan(int now, int pre) {
 51     dfn[now] = low[now] = ++indx;
 52     st.push(now);
 53     ins[now] = 1;
 54     for(int i = first[now]; ~i; i = edge[i].next) {
 55         int to = edge[i].to;
 56         if(to == pre) {
 57             continue;
 58         }
 59         if(!dfn[to]) {
 60             tarjan(to, now);
 61             low[now] = min(low[now], low[to]);
 62             if(low[to] > dfn[now]) {
 63                 bridge++;
 64                 edge[i].cut = 1;
 65                 edge[i^1].cut = 1;
 66             }
 67         } else if(ins[to]) {
 68             low[now] = min(low[now], dfn[to]);
 69         }
 70     }
 71     if(dfn[now] == low[now]) {
 72         scc++;
 73         int top;
 74         do {
 75             top = st.top();
 76             st.pop();
 77             ins[top] = 0;
 78             belong[top] = scc;
 79         } while(top != now);
 80     }
 81 }
 82
 83 int main()
 84 {
 85     int u, v;
 86     while(~scanf("%d %d", &n, &m)) {
 87         init();
 88         memset(dfn, 0, sizeof(dfn));
 89         memset(ins, 0, sizeof(ins));
 90         memset(belong, 0, sizeof(belong));
 91         memset(degree, 0, sizeof(degree));
 92         indx = scc = 0;
 93         while(!st.empty()) {
 94             st.pop();
 95         }
 96         for(int i = 1; i<= m; i++ ) {
 97             scanf("%d %d", &u, &v);
 98             add_edge(u, v, 1);
 99             add_edge(v, u, 1);
100         }
101
102         tarjan(1, -1);
103
104         for(int i = 1; i <= n; i++ ) {
105             for(int j = first[i]; ~j; j = edge[j].next) {
106                 int from = i, to = edge[j].to;
107                 if(edge[j].cut) {
108                     degree[ belong[i] ]++;
109                 }
110             }
111         }
112         int ans = 0;
113         for(int i = 1; i <= scc; i++ ) {
114             if(degree[i] == 1) {
115                 ans ++;
116             }
117         }
118         ans = (ans + 1) / 2;
119         printf("%d\n", ans);
120     }
121
122     return 0;
123 }

2,点双联通

P3388 【模板】割点(割顶)

题目背景

割点

题目描述

给出一个n个点,m条边的无向图,求图的割点。

输入输出格式

输入格式:

第一行输入n,m

下面m行每行输入x,y表示x到y有一条边

输出格式:

第一行输出割点个数

第二行按照节点编号从小到大输出节点,用空格隔开

输入输出样例

输入样例#1:

6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6

输出样例#1:

1
5

说明

n,m均为100000

tarjan 图不一定联通!!!

注意这题实际数据范围比题目描述要大。

 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4 const int MAXN = 1e5 + 7;
 5 const int MAXM = 2e5 + 7;
 6
 7 int n, m, first[MAXN], sign, indx, scc;
 8
 9 int dfn[MAXN], low[MAXN], ins[MAXN], cut[MAXN];
10
11 //stack<int>stk;
12
13 struct Edge {
14     int to, w, next;
15 } edge[MAXM];
16
17 inline void init() {
18 //    for(int i = 0; i <= n; i++ ) {
19 //        first[i] = -1;
20 //    }
21     memset(first, -1, sizeof(first));
22     sign = 0;
23 }
24
25 inline void add_edge(int u, int v, int w) {
26     edge[sign].to = v;
27     edge[sign].w = w;
28     edge[sign].next = first[u];
29     first[u] = sign++;
30 }
31
32 inline void init_tarjan() {
33     for(int i = 0; i <= n; i++ ) {
34         dfn[i] = low[i] = ins[i] = cut[i] = 0;
35     }
36     indx = scc = 0;
37     //while(!stk.empty()) { stk.pop(); }
38 }
39
40 void tarjan(int now, int faz) {
41     low[now] = dfn[now] = ++indx;
42     int child = 0;
43     for(int i = first[now]; ~i; i = edge[i].next) {
44         int to = edge[i].to;
45         if(!dfn[to]) {
46             tarjan(to, faz);
47             low[now] = min(low[now], low[to]);
48             ///非根节点,如果dfn[to] <= low[to]那么它是割点
49             if(low[to] >= dfn[now] && now != faz) {
50                 cut[now] = 1;
51             }
52             if(now == faz) {
53                 child++;
54             }
55         }
56         low[now] = min(low[now], dfn[to]);
57     }
58     if(child >= 2 && now == faz) { ///根节点有两个以上子树的是割点
59         cut[now] = 1;
60     }
61 }
62
63 int main()
64 {
65     //freopen("testdata.in", "r", stdin);
66     while(~scanf("%d %d", &n, &m)) {
67         init();
68         init_tarjan();
69         for(int i = 1; i <= m; i++ ) {
70             int u, v;
71             scanf("%d %d", &u, &v);
72             add_edge(u, v, 1);
73             add_edge(v, u, 1);
74         }
75         for(int i = 1; i <= n; i++ ) {
76             if(!dfn[i]) {
77                 tarjan(i, i);
78             }
79         }
80         vector<int>vec;
81         for(int i = 1; i <= n; i++ ) {
82             if(cut[i]) {
83                 vec.push_back(i);
84             }
85         }
86         printf("%d\n", vec.size());
87         for(int i = 0; i < vec.size(); i++ ) {
88             printf("%d ", vec[i]);
89         }
90     }
91     return 0;
92 }

原文地址:https://www.cnblogs.com/Q1143316492/p/9195174.html

时间: 2024-10-15 22:56:19

双联通分量复习的相关文章

hihocoder #1190 : 连通性&#183;四 点双联通分量

http://hihocoder.com/problemset/problem/1190?sid=1051696 先抄袭一下 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内

[HDOJ4738]Caocao&#39;s Bridges(双联通分量,割边,tarjan)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 给一张无向图,每一条边都有权值.找一条割边,使得删掉这条边双连通分量数量增加,求权值最小那条. 注意有重边,ACEveryDay里群巨给的意见是tarjan的时候记录当前点是从哪条边来的. 注意假如桥的权值是0的时候也得有一个人去炸…… 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7

UVA - 10765 Doves and bombs (双联通分量)

链接 :  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34798 给N个点的无向图并且联通,问删除每次一个点之后还剩多少联通分量. 找割顶 如果删除的是割顶 联通分量就会增加,否则还是1(因为原图是联通图),删除割顶之后 联通块的数目 就要看该割顶在几个双联通分量里出现过. #pragma comment(linker, "/STACK:10240000,10240000") #include <a

【POJ 2942】Knights of the Round Table(双联通分量+染色判奇环)

[POJ 2942]Knights of the Round Table(双联通分量+染色判奇环) Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 11661   Accepted: 3824 Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, an

HDU5409---CRB and Graph 2015多校 双联通分量缩点

题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分量则该边一定是桥, 那么我们可以先处理出所有的桥,然后把所有双联通分量缩点,缩点之后就变成了一棵树. 而树上的每一条边都是一个桥, 考虑每条边的输出,删除某一边后肯定会出现两个联通分量, 需要记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则ma

BZOJ2730 矿场搭建 解题报告 点双联通分量

题意概述: 一张有向图,在其中设置一些关键点(即题目中的逃生出口),使得删除任意一个点之后其余点都可以到达至少一个关键点. 问至少需要设置多少中关键点,有多少种设置方法. 解析: 首先,这道题要求删掉一个点,不难想到这道题与割点有关.其次,删掉一个点其他点仍然可以到达关键点就可以想到是点双联通分量. 但是,问题关键是,真的需要在每一个点双联通分量中都设置一个关键点吗? 答案是否定的,因为如果一个双联通分量连接了两个或两个以上的割点,一个割点被删掉那么还可以通过另外的割点到达某个关键点,如上图,红

POJ 1515 双联通分量

点击打开链接 题意:给一个联通的无向图,然后问你将其中的边变为有向的,加边使其变成有向的联通图 思路:若无向图有双联通分量,那么这个分量里的元素可以变成有向图的强联通,这应该很好看出来,然后需要加的边是什么呢,就是这个图上的桥呗,是桥的话变成有向的就要加一条边,然后剩下的无向图的双联通分量可以用dfs搜一下,边搜边输出就可以了,将桥记录下来遇到桥的时候特殊处理一下,然后双联通分量里的边每一条只能走一次,将走得边和反向边标记一下就行了  PS:vector写这样反向边的真是麻烦 #include

HDU 4612 双联通分量+树的直径

点击打开链接 题意:给一个无向联通图,里面可能有重边,问添加一条边后,使得图中的桥最小,将桥的数量输出 思路:刚刚读完题,就有了思路去写,无非就是将联通图双联通分量后缩点,然后求一条最长的路,首尾相连,肯定将更多的桥包含使得这些桥不再是桥,很好想的题,但是错了20+什么鬼,md重边这么难处理,醉了~~~,之前的做法是将重边全部找出来,希望数据弱点水过去算了,TLE好样的,那么我们在处理桥的时候,也就是找桥的时候,如果是桥,我们将这条边标记一下,然后找所有边时加上就行了,在一个就是找树的直径,两次

HDU 4738 Caocao&#39;s Bridges(双联通分量+并查集)

大意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去. 思路:我们就是要缩点后直接求桥上人的最少数量.(PS:1.注意图如果不联通直接输出0.2.如果图中的桥上人为0,个那么要让一个人去.3.重边的问题.这里可以忽略) #include<map> #include<queue> #include<cmath> #include<cstdio> #include<stac