大致题意:

为了保护放牧环境,避免牲畜过度啃咬同一个地方的草皮,牧场主决定利用不断迁移牲畜进行喂养的方法去保护牧草。然而牲畜在迁移过程中也会啃食路上的牧草,所以如果每次迁移都用同一条道路,那么该条道路同样会被啃咬过度而遭受破坏。

现在牧场主拥有F个农场,已知这些农场至少有一条路径连接起来(不一定是直接相连),但从某些农场去另外一些农场,至少有一条路可通行。为了保护道路上的牧草,农场主希望再建造若干条道路,使得每次迁移牲畜时,至少有2种迁移途径,避免重复走上次迁移的道路。已知当前有的R条道路,问农场主至少要新建造几条道路,才能满足要求?

 
错误做题思路: 求出桥的个数n,也应该考虑重边的情况. 结果应该是 (n + 1) / 2;
但是这样做是错误的 仅仅考虑桥是不可行的
比如一个最简单的图    1-> 2 -> 3 ->4  根据我们的上述结果我们得到 3 个桥,也就是说需要加 两条边就行了, 其实 我们只要将 1 - 4相连就行了。
因此我们上面的结论是错误的。
(思考问题要细心要仔细要全面)
 
正确思路:  要先将图 强联通分量缩点, 在无向图中我们称为边双连通分量。 将所有边双连通分量求出来缩成点,就形成了一棵树,我们只要判断树的叶子结点的个数就行了。
                    假设叶子节点的个数是 n  那么 就有 (n+1)/2 条边就能将这个图变成没有桥的 双连通图
                    判断一个点是否是叶子节点 只要判断这个点的度就行了,度为 1 的点就是叶子节点。
 
 
知识汇总:
求桥:
在求割点的基础上吗,假如一个边没有重边(重边 1-2, 1->2 有两次,那么 1->2 就是有两条边了,那么 1->2就不算是桥了)。
当且仅当 (u,v) 为父子边,且满足 dfn[u] < low[v]
我们求一个边双连通分支,在网上有人说在进行完 Tarjan  之后  根据 low 的值 直接划分边双分支,其实这个是不可行的,下面是反例
 
数据 
4 5
1 2
1 3
2 3
2 4
3 4
 
根据上图我们可以看出来, 他们是属于一个边双连通的分支,但是呢 low值 却是不一样的。
 
这里我们求边双连通分支是和求强联通分支是一样的,但是还有一点区别,其实我们没有必要再标记这个点是否在栈中。
因为我们的边是双向的, 单向的无法确定 u->v   v一定能到 u ? 
 
标价重边:
在这里使用了一个标志变量 K,  假如这个点到父亲的路有两条, 那么我 第一条可以不走,但是第二条必须要走,因为是重边,这样我的儿子节点也就可以更新 low 了。
 
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <cstring>
usingnamespace std;
#define INF 0xfffffff
#define maxn 10025
#define min(a,b) (a<b?a:b)
int m, n, Time, cnt, top;
int dfn[maxn], block[maxn], low[maxn], Father[maxn], Stack[maxn];
vector<int> G[maxn];
void init()
{
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low));
memset(block, , sizeof(block));
memset(Father, , sizeof(Father));
top = Time = cnt = ; for(int i=; i<=n; i++)
G[i].clear();
}
void Tarjan(int u,int fa)
{
dfn[u] = low[u] = ++Time;
Father[u] = fa;
Stack[top++] = u;
int len = G[u].size(), v, k = ; for(int i=; i<len; i++)
{
v = G[u][i];
if(v == fa && !k)
{
k ++;
continue;
} if(!low[v])
{
Tarjan(v, u);
low[u] = min(low[u], low[v]);
}
else
low[u] = min(low[u], dfn[v]);
} if(dfn[u] == low[u])
{
do
{
v = Stack[--top];
block[v] = cnt;
}while(u != v);
cnt ++;
}
} void solve()
{
int i, degree[maxn] = {}, ans = ;
for(i=; i<=n; i++)
{
if( !low[i] )
Tarjan(i, i);
} for(i=; i<=n; i++)
{
int v = Father[i];
if(block[i] != block[v])
{
degree[block[i] ] ++;
degree[block[v] ] ++;
}
} for(i=; i<cnt; i++)
{
if(degree[i] == )
ans ++;
}
printf("%d\n", (ans+)/ );
} int main()
{
while(scanf("%d %d",&n, &m) != EOF)
{
init();
while(m --)
{
int a, b;
scanf("%d %d",&a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
solve();
}
return0;
}
 
 
 
 
 
 

POJ 3177 Redundant Paths(重边标记法,有重边的边双连通分支)的更多相关文章

  1. tarjan算法求桥双连通分量 POJ 3177 Redundant Paths

    POJ 3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12598   Accept ...

  2. POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)

    POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的.一份代码能交.给定一个连通无向图,问加几条边能使得图变成一个双连通图 ...

  3. POJ 3177 Redundant Paths(边双连通的构造)

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13717   Accepted: 5824 ...

  4. POJ 3177——Redundant Paths——————【加边形成边双连通图】

    Redundant Paths Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Sub ...

  5. POJ 3177 Redundant Paths & POJ 3352 Road Construction(双连通分量)

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

  6. [双连通分量] POJ 3177 Redundant Paths

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13712   Accepted: 5821 ...

  7. poj 3177 Redundant Paths

    题目链接:http://poj.org/problem?id=3177 边双连通问题,与点双连通还是有区别的!!! 题意是给你一个图(本来是连通的),问你需要加多少边,使任意两点间,都有两条边不重复的 ...

  8. POJ 3177 Redundant Paths POJ 3352 Road Construction

    这两题是一样的,代码完全一样. 就是给了一个连通图,问加多少条边可以变成边双连通. 去掉桥,其余的连通分支就是边双连通分支了.一个有桥的连通图要变成边双连通图的话,把双连通子图收缩为一个点,形成一颗树 ...

  9. poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11047   Accepted: 4725 ...

  10. POJ - 3177 Redundant Paths(边双连通分支)(模板)

    1.给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图. 2. 3. //边双连通分支 /* 去掉桥,其余的连通分支就是边双连通分支了.一个有桥的连通图要变成边双连通图的话, 把双连通子图 ...

随机推荐

  1. jQuery失去焦点的时候注册验证

    //注册验证$('form :input').blur(function () { if ($("#txtName").val() == "") { $(&qu ...

  2. 搞一个app需要多久?

    //转载文章,看后有感 我有些尴尬地拿着水杯,正对面坐着来访的王总,他是在别处打拼的人,这几年据说收获颇丰,见移动互联网如火如荼,自然也想着要进来干一场,尽管王总从事的行当也算跟IT沾边,但毕竟太长时 ...

  3. Python:标准数据类型6种

    #!/usr/bin/python3 #python的基本语法和数据类型 #python3中 一行有多个语句,用分号分割(;) print("aaa") ;print(" ...

  4. java_设计模式_观察者模式_Observer Pattern(2016-07-27)

    看了好几篇文章,最终还是觉得<Head First 设计模式>举得例子比较符合观察者模式. 观察者模式概述: 观察者模式有时被称作发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者 ...

  5. login-登录

    <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Inse ...

  6. jQuery-弹窗登录

    在jQuery中实现弹窗常要用到的方法有: width()  :元素的宽度 outerWidth()  元素的宽度 盒子的padding+border 总的宽度 scrollTop()  鼠标滚轮自上 ...

  7. C# 程序性能提升篇-2、类型(字段类型、class和struct)的错误定义所影响性能浅析

    前景提要: 编写程序时,也许你不经意间,就不知不觉的定义了错误的类型,从而发生了额外的性能消耗,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环.网络程序(不断请求处理的)等这些时候 ...

  8. 简单工厂模式的C++实现

    用简单工厂模式实现一个计算器类: #include <iostream> #include <string> using namespace std; class Operat ...

  9. centos jdk切换

        #这里找下载路径 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html    ...

  10. windows系统安装ubuntu后,grub中没有windows启动项

    我的问题: 安装系统时候,选择grub安装在sdb磁盘 http://forum.ubuntu.org.cn/viewtopic.php?f=139&t=474289&start=15 ...