| Time Limit: 1000MS | Memory Limit: 65536K | |
Description
Input
Output
Sample Input
7 7 1 2 2 3 3 4 2 5 4 5 5 6 5 7
Sample Output
2
Hint
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。
统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边双连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。“ --BYVoid
/*
* ID: j.sure.1
* PROG:
* LANG: C++
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define Mem(f, x) memset(f, x, sizeof(f))
#define PB push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 5e3+5, M = 2e4+5;
struct Edge {
int v, next, idx, tag;
Edge(){}
Edge(int _v, int _next, int _idx, int _tag = 0):
v(_v), next(_next), idx(_idx), tag(_tag){}
}e[M];
int n, m, deep, tot, bcc_cnt;
int dfn[N], head[N], bcc_id[N], line[N][2], deg[N];
bool isbri[M];
void __init__()
{
bcc_cnt = tot = deep = 0;
for(int i = 0; i < n; i++) {
head[i] = -1;
deg[i] = dfn[i] = bcc_id[i] = 0;
}
Mem(isbri, 0);
}
void add(int u, int v, int idx)
{
int p;
for(p = head[u]; ~p; p = e[p].next) {
if(e[p].v == v) {
e[p].tag++;
return ;
}
}
e[tot] = Edge(v, head[u], idx);
head[u] = tot++;
}
int dfs(int u, int fa)
{
int lowu = dfn[u] = ++deep;
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(!dfn[v]) {
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if(lowv > dfn[u] && !e[i].tag)
isbri[e[i].idx] = 1;
}
else if(dfn[v] < dfn[u] && v != fa)
lowu = min(lowu, dfn[v]);
}
return lowu;
}
void flood(int u)
{
bcc_id[u] = bcc_cnt;
for(int i = head[u]; ~i; i = e[i].next) {
if(isbri[e[i].idx]) continue ;
int v = e[i].v;
if(!bcc_id[v]) {
flood(v);
}
}
}
int main()
{
#ifdef J_Sure
freopen("000.in", "r", stdin);
//freopen("999.out", "w", stdout);
#endif
while(~scanf("%d%d", &n, &m)) {
int ID = 0;
__init__();
for(int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
u--; v--;
line[i][0] = u; line[i][1] = v;
add(u, v, ID);
add(v, u, ID++);
}
dfs(0, -1);
for(int i = 0; i < n; i++) {
if(!bcc_id[i]) {
bcc_cnt++;
flood(i);
}
}
for(int i = 0; i < m; i++) {
int u = bcc_id[line[i][0]], v = bcc_id[line[i][1]];
if(u != v) {
deg[u]++; deg[v]++;
}
}
int ans = 0;
for(int i = 1; i <= bcc_cnt; i++) {
if(deg[i] == 1) ans++;
}
printf("%d\n", (ans+1)/2);
}
return 0;
}【连通图|边双连通+缩点】POJ-3177 Redundant Paths
原文地址:http://blog.csdn.net/j_sure/article/details/42211879