题目大意:求无向图的割边编号。

割边定义:在一个连通图中,如果删去一个边e,图便变成不连通的两个部分,则e为该图的割边。

求法:边(u,v) 不是割边,当且仅当边(u,v)在一个环内。因此所有不在环内的边就是割边,我们要找到它。对图进行Dfs,对每个节点盖上时间戳DfsN,Dfs的方式形成了一棵搜索树。不在环内的边一定在搜索树中(证明:假设不在环内边e不在搜索树中,则Dfs时要访问该边的to点就会经过另外一条边e'。Dfs的出发点是相同的,因此必然e,e'在一个环内),我们要找到它。如果边(u,v)(u->DfsN < v->DfsN)在一个环内,则v的子树中必然存在一节点a与u的祖先节点(包括u)用一个子树外的边相连(与a相连的每一条树外边的to点b都是v的祖先。证明:如果不是,在Dfs时,要么在站在v上向下搜索时把b纳为v的子树,要么在站在b上向下搜索时把v纳为v'的子树)。定义满足该条件的祖先节点们中DfsN最小的节点的DfsN值为u->Low,如果u->DfsN < v->Low,则边(u,v)是割边。易得:u->Low=min{u->DfsN, each v∈u的子节点且未被访问{v->Low},each e∈v树外边{e->To->DfsN}}。

特判:选边向下遍历时,如果e==曾经到达u的边的反向边,则跳过。因为两条边实际上是一条边。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAX_NODE = 10010, MAX_EDGE = 100010 * 2; struct Node;
struct Edge; struct Node
{
int Id, DfsN, Low;
Edge *Head;
}_nodes[MAX_NODE], *Root;
int _vCount, DfsCnt; struct Edge
{
Node *From, *To;
Edge *Next, *Rev;
bool IsCut;
Edge(){}
Edge(Node *from, Node *to, Edge *next)
:From(from),To(to),Next(next),IsCut(false){}
}*_edges[MAX_EDGE];
int _eCount; void Init(int vCount)
{
Root = 1 + _nodes;
_vCount = vCount;
_eCount = 0;
DfsCnt = 0;
memset(_nodes, 0, sizeof(_nodes));
} Edge *NewEdge()
{
_eCount++;
return _edges[_eCount] ? _edges[_eCount] : _edges[_eCount] = new Edge();
} Edge *AddEdge(Node *from, Node *to)
{
Edge *e = NewEdge();
e->From = from;
e->To = to;
e->Next = from->Head;
e->IsCut = false;
from->Head = e;
return e;
} void Build(int uId, int vId)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
Edge *e1 = AddEdge(u, v), *e2 = AddEdge(v, u);
e1->Rev = e2;
e2->Rev = e1;
} void Dfs(Node *u, Edge *prev)
{
u->DfsN = ++DfsCnt;
u->Low = u->DfsN;
for (Edge *e = u->Head; e; e = e->Next)
{
if (!e->To->DfsN)
{
Dfs(e->To, e);
u->Low = min(u->Low, e->To->Low);
if (u->DfsN < e->To->Low)
e->IsCut = e->Rev->IsCut = true;
}
else if (prev && e != prev->Rev)
u->Low = min(u->Low, e->To->DfsN);
}
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int testCase, totNode, totEdge, uId, vId;
scanf("%d", &testCase);
while (testCase--)
{
scanf("%d%d", &totNode, &totEdge);
Init(totNode);
for (int i = 1; i <= totEdge; i++)
{
scanf("%d%d", &uId, &vId);
Build(uId, vId);
}
Dfs(Root, NULL);
int ans[MAX_EDGE / 2 + 1], pAns = 0;
for (int i = 1; i <= _eCount; i+=2)
if (_edges[i]->IsCut)
ans[++pAns] = i;
printf("%d\n", pAns);
for (int i = 1; i < pAns; i++)
printf("%d ", (ans[i]+1)/2);
if(pAns)
printf("%d\n", (ans[pAns] + 1) / 2);
if (testCase)
printf("\n");
}
return 0;
}

  

  

最新文章

  1. ASP.NET MVC项目实践技巧
  2. easyui 汇总
  3. Spring中配置和读取多个Properties文件--转
  4. 牛B的调试工具:OzCode
  5. Linux文件权限查看及修改命令chmod
  6. 纯css3实现旋转的太极图
  7. git alias和gitconfig配置
  8. MMO可见格子算法
  9. 开源搜索引擎Iveely 0.7.0发布,不一样,那就让他不一样!
  10. hiho47 : 拓扑排序&#183;一
  11. java 拦截器和过滤器区别(转载)
  12. BZOJ3439: Kpm的MC密码
  13. debug jdk
  14. VS2010对C++11的支持列表(感觉大部分都不支持)
  15. Python内置方法的时间复杂度
  16. Java第五周总结
  17. CSS三种插入样式表格式
  18. LVDS接口分类,时序,输出格式
  19. keepalived实现haproxy负载均衡器的高可用
  20. wx事件处理二

热门文章

  1. Spring Boot (15) pom.xml设置
  2. 5.29MyBatis Generator
  3. Bootstrap中container与container-fluid的区别
  4. 拖入浏览器读取文件demo
  5. Emmet(Zen Coding)语法规则简介
  6. Android:JAVA使用HDF5存储
  7. IT狂人职场路:揭秘华为百度高管如何炼成?
  8. Laravel -- windows apache .htaccess https 路由重写
  9. LoadRunner中遭遇交互数据加密的处理方案
  10. HTML 1.1页面js修改文字颜色