POJ3177 Redundant Paths 图的边双连通分量
题目大意:问一个图至少加多少边能使该图的边双连通分量成为它本身。
图的边双连通分量为极大的不存在割边的子图。图的边双连通分量之间由割边连接。求法如下:
- 求出图的割边
- 在每个边双连通分量内Dfs,标记每个节点所属于的双连通分量编号
- 构建一新图Tree,一个节点代表一个双连通分量。原图中遍历割边,将割边连接的两个双连通分量在Tree中的对应节点连接。
- Tree中算出每个节点的度数,如果一节点度数为1,则其为叶子节点。输出(叶子节点数+1/2)。(连接了叶子节点,就形成了环,Tree中不连接叶子节点的边因为在环内,所以不再是割边了。)
注意:如果一个边是割边,则其反向边也是割边。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cassert>
using namespace std; #define LOOP(i, n) for(int i=1; i<=n; i++)
const int MAX_NODE = 5010, MAX_EDGE = 10010 * 2; struct G {
struct Node;
struct Edge; struct Node {
int Id, DfsN, Low, InBlock, Degree;
Edge *Head;
}_nodes[MAX_NODE], *Root; struct Edge {
bool IsCut;
Node *From, *To;
Edge *Next, *Rev;
Edge(){}
Edge(Node *from, Node *to, Edge *next):From(from),To(to),Next(next),IsCut(false){}
}*_edges[MAX_EDGE]; int _vCount, _eCount, DfsCnt, BlockCnt, LeafCnt; void Init() {
memset(_nodes, 0, sizeof(_nodes));
_vCount = _eCount = DfsCnt = LeafCnt = 0;
BlockCnt = 0;
} Edge *NewEdge() {
_eCount++;
return _edges[_eCount] ? _edges[_eCount] : _edges[_eCount] = new Edge();
} Edge *AddEdge(Node *from, Node *to) {
Edge *e = NewEdge();
*e = Edge(from, to, from->Head);
from->Head = e;
return e;
} void Build(int uId, int vId, bool is2d) {
while (_vCount < uId || _vCount < vId)
_vCount++;
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
Edge *e1 = AddEdge(u, v);
if (is2d) {
Edge *e2 = AddEdge(v, u);
e1->Rev = e2;
e2->Rev = e1;
}
} void FindCutEdge(Node *u, Edge *Prev) {//易忘点:prev
if (u->DfsN)
return;
u->DfsN = u->Low = ++DfsCnt;
for (Edge *e = u->Head; e; e = e->Next) {
if (!e->To->DfsN) {
FindCutEdge(e->To, e);
u->Low = min(u->Low, e->To->Low);
if (u->DfsN < e->To->Low)
e->IsCut = e->Rev->IsCut = true;//易忘点:e->Rev->IsCut
}
else if (e->Rev != Prev)
u->Low = min(u->Low, e->To->DfsN);
}
} void FindCutEdge() {
LOOP(i, _vCount) {//易忘点:图不一定连通,所以要循环。
Root = i + _nodes;
FindCutEdge(Root, NULL);
}
} void SetBlock(Node *u) {
u->InBlock = BlockCnt;
for (Edge *e = u->Head; e; e = e->Next)
if (!e->IsCut && !e->To->InBlock)
SetBlock(e->To);
} void SetBlock() {
LOOP(i, _vCount) {
if (!_nodes[i].InBlock) {
BlockCnt++;
SetBlock(i + _nodes);
}
}
}
void SetLeafCnt() {//此处比较有技巧,注意看看
LOOP(i, _eCount)
_edges[i]->To->Degree++;
LOOP(i, _vCount)
if (_nodes[i].Degree <= 1)
LeafCnt++;
}
}Org, Tree; int main() {
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
//freopen("c:\\noi\\source\\output.txt", "w", stdout);
#endif
Org.Init();
Tree.Init();
int totNode, totEdge, uId, vId;
scanf("%d%d", &totNode, &totEdge);
LOOP(i, totEdge) {
scanf("%d%d", &uId, &vId);
Org.Build(uId, vId, true);
}
Org.FindCutEdge();
Org.SetBlock();
LOOP(i, Org._eCount)
if (Org._edges[i]->IsCut)
Tree.Build(Org._edges[i]->From->InBlock, Org._edges[i]->To->InBlock, false);
Tree.SetLeafCnt();
printf("%d\n", (Tree.LeafCnt + 1) / 2);
return 0;
}
POJ3177 Redundant Paths 图的边双连通分量的更多相关文章
- POJ 3177 Redundant Paths (tarjan边双连通分量)
题目连接:http://poj.org/problem?id=3177 题目大意是给定一些牧场,牧场和牧场之间可能存在道路相连,要求从一个牧场到另一个牧场要有至少两条以上不同的路径,且路径的每条pat ...
- POJ 3177 Redundant Paths (桥,边双连通分量,有重边)
题意:给一个无向图,问需要补多少条边才可以让整个图变成[边双连通图],即任意两个点对之间的一条路径全垮掉,这两个点对仍可以通过其他路径而互通. 思路:POJ 3352的升级版,听说这个图会给重边.先看 ...
- BZOJ1718:[USACO]Redundant Paths 分离的路径(双连通分量)
Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numb ...
- POJ3177 Redundant Paths【tarjan边双联通分量】
LINK 题目大意 给你一个有重边的无向图图,问你最少连接多少条边可以使得整个图双联通 思路 就是个边双的模板 注意判重边的时候只对父亲节点需要考虑 你就dfs的时候记录一下出现了多少条连向父亲的边就 ...
- poj3352 Road Construction & poj3177 Redundant Paths (边双连通分量)题解
题意:有n个点,m条路,问你最少加几条边,让整个图变成边双连通分量. 思路:缩点后变成一颗树,最少加边 = (度为1的点 + 1)/ 2.3177有重边,如果出现重边,用并查集合并两个端点所在的缩点后 ...
- poj3177 Redundant Paths 边双连通分量
给一个无向图,问至少加入多少条边能够使图变成双连通图(随意两点之间至少有两条不同的路(边不同)). 图中的双连通分量不用管,所以缩点之后建新的无向无环图. 这样,题目问题等效于,把新图中度数为1的点相 ...
- POJ3177 Redundant Paths 双连通分量
Redundant Paths Description In order to get from one of the F (1 <= F <= 5,000) grazing fields ...
- POJ3177 Redundant Paths(边双连通分量+缩点)
题目大概是给一个无向连通图,问最少加几条边,使图的任意两点都至少有两条边不重复路径. 如果一个图是边双连通图,即不存在割边,那么任何两个点都满足至少有两条边不重复路径,因为假设有重复边那这条边一定就是 ...
- POJ3177 Redundant Paths —— 边双联通分量 + 缩点
题目链接:http://poj.org/problem?id=3177 Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total ...
随机推荐
- 使用IDEA 搭建一个SpringBoot + Hibernate + Gradle
---恢复内容开始--- 打开IDEA创建一个新项目: 第一步: 第二步: 第三步: 最后一步: 如果下载的时候时间太久.可以找到build.gradle文件,添加以下代码.如下图 maven{ ur ...
- 【java基础】(3)Java继承内存分配
继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法. (3)子类中定义的成员变量和父类中定义 ...
- 高通处理器手机 解锁Bootloader 教程
目前很多手机都需要解锁Bootloader之后才能进行刷机操作 本篇教程教你如何傻瓜式解锁Bootloader 首先需要在设置-关于手机 找到版本号(个别手机可能是内核版本号,甚至其他) 然后 快 ...
- MyEclipse加入jquery.js文件missing semicolon的错误
今天打开项目,发现有一个小红叉,虽然不影响项目的编译和运行,但是看着非常影响心情.原因是jquery-1.8.2.min.js报了一堆missing semicolon的错误.之所以会这样,其实是My ...
- [转]常用Git命令清单
原文地址:http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html 作者: 阮一峰 日期: 2015年12月 9日 我每天使用 Git , ...
- AI不与人为敌
业界广为流传着一句话:有多少人工就有多少智能. 其实还应该有一句话:有多少付出就因该有多少回报.公正是世界永恒的话题. 一.人工智能还是人工愚蠢 科技从来没有善恶,也不会杀人,愚蠢的人比聪明的人做的错 ...
- Python学习①. 基础语法
Python 简介 Python 是一种解释型,面向对象的语言.特点是语法简单,可跨平台 Python 基础语法 交互式编程 交互式编程不需要创建脚本文件,是通过 Python 解释器的交互模式进来编 ...
- android全屏下的输入框未跟随软键盘弹起问题
最近开发中遇到,全屏模式下输入框在底部不会跟随软键盘弹起.于是网上搜索了解决的方案.大致找到了两种方案. 第一种 定义好此类 public class SoftKeyBoardListener { p ...
- Python画三维图-----插值平滑数据
一.二维的插值方法: 原始数据(x,y) 先对横坐标x进行扩充数据量,采用linspace.[如下面例子,由7个值扩充到300个] 采用scipy.interpolate中的spline来对纵坐标数据 ...
- C语言右移操作在汇编层面的相关解释
在 CSDN 看到帖子回复如下: x=y>>2;004122A8 mov eax,dword ptr [y] 004122AB sar eax,2 '算 ...