[双连通分量]poj1679 Road Construction
来源:互联网 发布:淘宝怎么联系卖家客服 编辑:程序博客网 时间:2024/05/17 09:08
题意
给出一个连通的无向图,求至少增加多少条边让这个图变成边双连通图
思路
其实题目意思很清晰很明白,但是怎么操作才是重点。
那么首先先想想怎么把整个图简化一下, 先求一次边双连通分量。
因为边双连通分量本来就是个边双连通图,那么这里面无论怎样增边,都是无意义的,那么就可以把它缩成一个点。
将所有的边双连通分量都缩成一个点之后,原图变成了一棵树。
那么,如何让一棵树变成一个双连通图,是一个问题。
在网上很容易找到要增加的边就等于叶子的数量加一的和除以二,这里设叶子的数量为
怎么证明是个问题啊……
其实很容易想到,在一棵树上面,选取到根节点最远的两个叶子节点,然后它们之间连一条边,就可以发现这里产生了一个环,这个环是双连通的。容易发现,如果换成其他的加边的方法, 都没有这种方法产生的环所含的节点多(或一样多),所以这样做一定是最优的。
然后把这个环缩成一个点,然后把这个点作为原图的根节点,然后反复操作,最终得到的答案就是加了
但是为什么叶子的个数总是为1<-_<-
,有待思考<-_<-
,或者哪个大神来解答都行<-_<-
代码
关于代码,其实是有些和之前求点双连通分量是不太一样的。
因为可以用更加简单的方式去求。
首先先找到原图中所有的桥,然后桥把原图分成了许多双连通分量,即去掉桥之后,剩下的连通分量刚好对应原图的双连通分量
找到桥之后做dfs,标记点,注意别经过桥就可以了
然后找叶子这一块,其实缩点之后是可以不用考虑的,直接把所属的双连通分量的标号拿来就用
然后统计每一个子节点的度数,因为是无向图嘛,所以总度数为2的点就只连了一条边,也就是叶子节点了。
#include <algorithm>#include <cstring>#include <cstdio>#include <queue>using namespace std;const int MAXN = 5010, MAXM = 20010;struct Edge { int u, v, ne;} e[MAXM];int head[MAXN];int n, m;int m_cnt;int bcc_cnt, pre[MAXN], low[MAXN], dfs_clock, bccno[MAXN];bool is_bridge[MAXM];int d[MAXN];int dfs(int u, int fa) { int lowu = pre[u] = ++dfs_clock; for(int i = head[u]; ~i; i = e[i].ne) { int v = e[i].v; if(!pre[v]) { int lowv = dfs(v, u); lowu = min(lowu, lowv); if(lowv > pre[u]) { is_bridge[i] = 1; is_bridge[i ^ 1] = 1; } } else { if(pre[v] < pre[u] && v != fa) { lowu = min(lowu, pre[v]); } } } low[u] = lowu; return lowu;}void dfs2(int u) { if(bccno[u]) { return ; } bccno[u] = bcc_cnt; for(int i = head[u]; ~i; i = e[i].ne) { if(!is_bridge[i]) { dfs2(e[i].v); } }}void find_bcc(int n) { memset(pre, 0, sizeof pre); memset(is_bridge, 0, sizeof is_bridge); dfs_clock = 0; for(int i = 1; i <= n; ++i) { if(!pre[i]) { dfs(i, -1); } } memset(bccno, 0, sizeof bccno); bcc_cnt = 1; for(int i = 1; i <= n; ++i) { if(!bccno[i]) { dfs2(i); ++bcc_cnt; } }}void AddEdge(int u, int v) { e[m_cnt].u = u; e[m_cnt].v = v; e[m_cnt].ne = head[u]; head[u] = m_cnt++;}void init() { memset(head, -1, sizeof head); m_cnt = 0;}int main(void) { init(); scanf("%d%d", &n, &m); for(int i = 0; i < m; ++i) { int u, v; scanf("%d%d", &u, &v); AddEdge(u, v); AddEdge(v, u); } find_bcc(n); for(int i = 1; i <= n; ++i) { for(int j = head[i]; ~j; j = e[j].ne) { if(bccno[i] != bccno[e[j].v]) { d[bccno[i]]++; d[bccno[e[j].v]]++; } } } int cnt = 0; for(int i = 1; i < bcc_cnt; ++i) { if(d[i] == 2) { cnt++; } } printf("%d\n", (cnt + 1) >> 1); return 0;}
- [双连通分量]poj1679 Road Construction
- [双连通分量]poj 3352 Road Construction
- poj 3352--Road Construction(双连通分量)
- POJ---3352-Road Construction(双连通分量)
- POJ3352 Road Construction (双连通分量)
- poj3352 Road Construction(边双连通分量)
- POJ3352 Road Construction 双连通分量和桥 tarjan
- POJ 3352 Road Construction / 边双连通分量
- POJ 3352 Road Construction(边双连通分量)
- POJ 3352 Road Construction (边双连通分量)
- poj 3352 Road Construction 边双连通分量
- POJ3352.Road Construction——边-双连通分量
- POJ 3352 Road Construction(边双连通分量)
- POJ - 3352 Road Construction(边双连通分量)
- POJ-3352 Road Construction (边双连通分量[Tarjan])
- poj 3352 Road Construction 双连通分量+缩点 模板
- poj 3352 Road Construction(边-双连通分量)
- poj 3352 Road Construction(边双连通分量)
- Java小游戏之控制台小游戏
- 1094. The Largest Generation (25)广搜
- 【前端入门】前端基本概念
- Zookeeper学习笔记(三)-Zookeeper的配置
- 微信小程序开发SSL证书相关问题
- [双连通分量]poj1679 Road Construction
- 学以致用——通过方差系数比较不同股票的估价离散程度
- java-StackDemo
- Ubuntu16安装Android Studio过程
- 算法-获取链表中倒数第k个结点
- ThreadLocal 线程局部变量
- 我的Android逆向之路(一)
- 软件联盟社团介绍
- hmtl