题目大意:问一个图至少加多少边能使该图的边双连通分量成为它本身。

图的边双连通分量为极大的不存在割边的子图。图的边双连通分量之间由割边连接。求法如下:

  1. 求出图的割边
  2. 在每个边双连通分量内Dfs,标记每个节点所属于的双连通分量编号
  3. 构建一新图Tree,一个节点代表一个双连通分量。原图中遍历割边,将割边连接的两个双连通分量在Tree中的对应节点连接。
  4. 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 图的边双连通分量的更多相关文章

  1. POJ 3177 Redundant Paths (tarjan边双连通分量)

    题目连接:http://poj.org/problem?id=3177 题目大意是给定一些牧场,牧场和牧场之间可能存在道路相连,要求从一个牧场到另一个牧场要有至少两条以上不同的路径,且路径的每条pat ...

  2. POJ 3177 Redundant Paths (桥,边双连通分量,有重边)

    题意:给一个无向图,问需要补多少条边才可以让整个图变成[边双连通图],即任意两个点对之间的一条路径全垮掉,这两个点对仍可以通过其他路径而互通. 思路:POJ 3352的升级版,听说这个图会给重边.先看 ...

  3. BZOJ1718:[USACO]Redundant Paths 分离的路径(双连通分量)

    Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numb ...

  4. POJ3177 Redundant Paths【tarjan边双联通分量】

    LINK 题目大意 给你一个有重边的无向图图,问你最少连接多少条边可以使得整个图双联通 思路 就是个边双的模板 注意判重边的时候只对父亲节点需要考虑 你就dfs的时候记录一下出现了多少条连向父亲的边就 ...

  5. poj3352 Road Construction & poj3177 Redundant Paths (边双连通分量)题解

    题意:有n个点,m条路,问你最少加几条边,让整个图变成边双连通分量. 思路:缩点后变成一颗树,最少加边 = (度为1的点 + 1)/ 2.3177有重边,如果出现重边,用并查集合并两个端点所在的缩点后 ...

  6. poj3177 Redundant Paths 边双连通分量

    给一个无向图,问至少加入多少条边能够使图变成双连通图(随意两点之间至少有两条不同的路(边不同)). 图中的双连通分量不用管,所以缩点之后建新的无向无环图. 这样,题目问题等效于,把新图中度数为1的点相 ...

  7. POJ3177 Redundant Paths 双连通分量

    Redundant Paths Description In order to get from one of the F (1 <= F <= 5,000) grazing fields ...

  8. POJ3177 Redundant Paths(边双连通分量+缩点)

    题目大概是给一个无向连通图,问最少加几条边,使图的任意两点都至少有两条边不重复路径. 如果一个图是边双连通图,即不存在割边,那么任何两个点都满足至少有两条边不重复路径,因为假设有重复边那这条边一定就是 ...

  9. POJ3177 Redundant Paths —— 边双联通分量 + 缩点

    题目链接:http://poj.org/problem?id=3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total ...

随机推荐

  1. 导入不同业务数据通过Excel实现

    很多公司都用到了老系统移植到新系统,数据自然也需要迁移,这个解决方案之一就是使用Excel文件导入. 结合公司实现,然后简单写了个Demo. (PS:去找朋友本想着花几十分钟弄出来炫耀一波,结果花了三 ...

  2. Oracle 生成数据字典

    SELECT ROWNUM 序号,A.COLUMN_NAME AS "字段名称",B.comments AS "字段描述", A.DATA_TYPE as 字段 ...

  3. Mysql正则

    摘自:http://www.runoob.com/mysql/mysql-regexp.html 模式 描述 ^ 匹配输入字符串的开始位置.如果设置了 RegExp 对象的 Multiline 属性, ...

  4. js 检查内容是否为空

    var NoViods = document.getElementsByClassName("NoVoid"); ; i < NoViods.length; i++) { i ...

  5. API接口测试用例编写规则(转载)

    API接口测试用例编写规则 (1)必需参数覆盖.对于接口的参数,接口文档一般都会说明哪些儿是必需的,哪儿是非必需的.对于必需的参数,一定要测试传参数和不传参数接口是否报错? (2)必需的参数各种情况覆 ...

  6. 如何将一个已有的项目托管到github或是码云上?git的配置

    场景一:已有的一个项目,要把它托管到Git上去,步骤和方法如下: 方法一: ①在工程的路径下 : git init 建一个裸仓库. ②远程仓库地址 :将本地的仓库和远程仓库关联 git remote ...

  7. eas更改用户组织范围和业务组织范围

    表: T_PM_OrgRangeIncludeSubOrg 10 20 30 分别代表 业务组织 行政组织 以及管辖组织.查行政组织,

  8. 【剑指Offer】29、最小的K个数

      题目描述:   输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4.   解题思路:   本题最直观的解法就是将输入的n个整数排 ...

  9. [bzoj3507 Cqoi2014]通配符匹配 (hash+DP)

    传送门 Solution 显然用哈希233 设\(f[i][j]\)表示第i个通配符和当前第j个字符是否匹配 考虑两种通配符的特性,直接转移即可 Code #include <cstdio> ...

  10. 49.filter、query比较

    主要知识点 1.filter与query用在同一次查询中的语法 2.filter与query使用场景对比 3.二都的性能比较     一.filter与query示例 1.先准备数据 PUT /com ...