POJ3177 Redundant Paths
来源:互联网 发布:网页源代码加密js 编辑:程序博客网 时间:2024/06/01 23:45
一. 原题链接:http://poj.org/problem?id=3177
二. 题目大意:给一个无向图,要求添加一些边使得任意两点之间最少有2条不同的路径,不同的路径指的是没有公共边的路径。
三. 思路:
1. 我们知道任意一个边双连通分量,满足之中的两两点之间有2条不同的路径,其实利用Tarjan算法求边双连通分量也体现这种结果。假设父亲为u,子女为v,如果low[v]<=dfn[u],说明v可以回到u以及u以上的点,而u到v已经有一条路径了,于是u,v在同一个边双连通分量里面。
2. 于是问题转化成求出多少个边双连通分量,单独一个节点算一个,然后把每个双连通分量看成一个点,也就是缩点,这时候变成了一棵树(无回路),树的叶子节点到叶子节点直接肯定只有一条路径,因为它是叶子节点,要走到另一个叶子节点一定要先返回根,于是我们要做的只需要把叶子节点全部连成一个边双连通图,而n个叶子节点,需要(n+1)/2条边,其实叶子节点就是度为1的边。
3. 于是我们可以用Tarjan求出原图的各个边双连通分量,用并查集把同一连通分量的节点(low[u] <= dfn[v])集合起来,同时求出所有的桥(low[u]>dfn[v]),就是缩点后的树的边。用一个数组blong把所有的边双连通分量标号,然后扫一遍,数出各个双连通分量的度,度为1的个数就是树的叶子节点。然后结果就出来了。
四.代码
#include <iostream>#include <cstdio>#include <queue>#include <cstring>#include <cmath>#include <cstdlib>using namespace std;const int MAX_N = 5008, INF = 0x3f3f3f3f;class AdjList{public: struct Edge { int v, next; }edges[MAX_N*MAX_N]; int head[MAX_N], cnt; void init() { cnt = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { edges[cnt].v = v, edges[cnt].next = head[u]; head[u] = cnt++; }};class FUset{public: int pre[MAX_N]; void init() { memset(pre, -1, sizeof(pre)); } int Find(int x) { int root = x, save; for(; pre[root] >= 0; root = pre[root]); for(save = pre[x]; x != root; pre[x] = root, x = save, save = pre[x]); return root; } void Union(int x, int y) { int Rootx = Find(x), Rooty = Find(y); int temp = pre[Rootx] + pre[Rooty]; if(pre[Rootx] > pre[Rooty]){ pre[Rootx] = Rooty; pre[Rooty] = temp; } else{ pre[Rooty] = Rootx; pre[Rootx] = temp; } }};class Tarjan{public: AdjList graph; FUset FU; int bridge[MAX_N][2], low[MAX_N], dfn[MAX_N], nBridge, nodeNum, belong[MAX_N];//every node belong to which double connection. bool visited[MAX_N]; void init(int n) { nodeNum = n; nBridge = 0; graph.init(); FU.init(); memset(visited, 0, sizeof(visited)); memset(belong, -1, sizeof(belong)); } void dfs(int pre, int u, int depth) { visited[u] = true; low[u] = dfn[u] = depth; bool toPre = false; int i, v; for(i = graph.head[u]; i != -1; i = graph.edges[i].next){ v = graph.edges[i].v; if(!visited[v]){ dfs(u, v, depth + 1); low[u] = min(low[u], low[v]); if(low[v] <= dfn[u])//able to return, belong to the same double connection. FU.Union(u, v); if(low[v] > dfn[u])//unable to return, (u, v) is a bridge. bridge[nBridge][0] = u, bridge[nBridge++][1] = v; } else if(v != pre || toPre) low[u] = min(low[u], dfn[v]); else if(v == pre) toPre = true; } } int doubleConnection() { int i, root, res = 0; dfs(-1, 1, 1); for(i = 1; i <= nodeNum; i++){ root = FU.Find(i); if(belong[root] == -1) belong[root] = res++; belong[i] = belong[root]; } return res; } int getRes() { int cnt[MAX_N] = {0}, i, num, u, v, res = 0; num = doubleConnection(); for(i = 0; i < nBridge; i++){ u = bridge[i][0]; v = bridge[i][1]; cnt[belong[u]]++, cnt[belong[v]]++; } for(i = 0; i < num; i++) if(1 == cnt[i]) res++; return res; }}G;int main(){ //freopen("in.txt", "r", stdin); int i, u, v, F, R; while(~scanf("%d%d", &F, &R)){ G.init(F); for(i = 0; i < R; i++){ scanf("%d%d", &u, &v); G.graph.addEdge(u, v); G.graph.addEdge(v, u); } printf("%d\n", (G.getRes()+1)/2); } return 0;}
0 0
- poj3177 - Redundant Paths
- POJ3177--Redundant Paths
- 【POJ3177】Redundant Paths
- poj3177 Redundant Paths
- poj3177 Redundant Paths
- POJ3177 Redundant Paths
- POJ3177 Redundant Paths
- 【poj3177】 Redundant Paths
- poj3177 Redundant Paths
- Redundant Paths(POJ3177)
- 【poj3177】【双连通分量】Redundant Paths
- poj3177 Redundant Paths 边双连通分量
- POJ3177 Redundant Paths (双联通缩点)
- poj3177 Redundant Paths && poj3352 Road Construction
- poj3177 Redundant Paths 双连通分量
- poj3177 Redundant Paths 双连通分量
- poj3177 Redundant Paths(边双联通)
- [POJ3177]Redundant Paths(tarjan求边双)
- JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet
- 【深入理解JVM】:解析与分派
- Java之------JUnit(二)
- PaperReading:Object Co-Segmentation Based on Shortest Path Algorithm and Saliency Model
- CentOS6.5服务器端口捆绑
- POJ3177 Redundant Paths
- 数据库(SQLite)
- Hadoop之多行读取数据
- RxJava使用(二)filter 操作符
- NYOJ 三点顺序--68
- HDU1050 贪心
- IE7-span折行问题
- 多线程与线程池总结
- Android客户端多文件上传