题意:给一个无向图,问需要补多少条边才可以让整个图变成【边双连通图】,即任意两个点对之间的一条路径全垮掉,这两个点对仍可以通过其他路径而互通。

思路:POJ 3352的升级版,听说这个图会给重边。先看3352的题解http://www.cnblogs.com/xcw0754/p/4619594.html。

  其实与3352不同的就是重边出现了怎么办?假如出现的重边刚好是桥呢?

  首先要知道,【割点】可以将两个【点双连通分量】隔开来,因为仅一个【点双连通分量】中肯定无割点,那么每两个点对都同时处于若干个简单环中才能当一个点撤掉仍然可以互通。

  而【桥】可以将两个【边双连通分量】隔开来,因为仅仅一个【边双连通分量】中肯定无桥,那么每两个点对之间肯定有多条路径可达(边都是不同的),当任意1条边撤掉后每两个点对仍然可达。

  以上两点很重要,根据第二点,我们知道,如果在一个【边双连通分量】中任意两个有边相连的点再添加任意条边都是不影响的,任意两点间依然有多条不同的【边】路径可达。但是如果桥出现了重边呢?那么该桥上的两点会同时属于一个【边双连通分量】,此时就会将两个【边双连通分量】合并为一。

  如何判别桥是否出现重边?我们一般以t!=far来判别是否遇到一条边通往父亲,但是现在要变了,我们要判断是否遇到这条边多次,如果多次,要更新本节点x的low值了,应该用low[x]=min(low[x],dfn[far])来更新,更新完之后他们的low值自然会处于同一个领导之下,此时再按照3352中用的类似于并查集的方法就可以将其彻底归到同一个【边双连通分量】中。

特别注意:求点双连通分量时要注意在t!=far前加上这个条件“ dfn[t]<dfn[x] ”。如果不求这个可以不加,因为t如果已经遍历过,且dfn[t]>dfn[x],那么肯定在x之上访问过,此时dfn[t]可能可以更新到low[x],但是如果dfn[t]<dfn[x],且在x之下访问过,那么dfn[t]肯定比dfn[x]还小,那肯定比low[x]小,则更新不到,也不产生影响,所以也不用去判断dfn[t]<dfn[x]。

 #include <iostream>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <set>
using namespace std;
const int N=+;
vector<int> vect[N];
int low[N], dfn[N], pre[N], cnter;
int du[N];
vector<pair<int,int> > cutt;
int find(int x) //寻找x的low值
{
if(low[x]==dfn[x]) return low[x];
return low[x]=find( pre[low[x] ] );
} void DFS(int x, int far)
{
low[x]= dfn[x]= ++cnter;
pre[cnter]=x; //第cnter个访问的是x
int times=; //记录桥是否有两条,若有,则要更新low值
for(int i=; i<vect[x].size(); i++)
{
int t=vect[x][i];
if(!dfn[t])
{
DFS(t,x);
low[x]=min(low[x],low[t]);
if(low[t]>dfn[x]) cutt.push_back(make_pair(x,t));
}
else if(t!=far) low[x]=min(low[x],dfn[t]);
else
{
if(times>) //重边,low应该更新为far才对。
low[x]=min(low[x],dfn[far]);
times++;
}
}
} int cal_bcc(int f) //找桥
{
cutt.clear();
memset(du,,sizeof(du));
memset(low,,sizeof(low));
memset(dfn,,sizeof(dfn));
memset(pre,,sizeof(pre));
cnter=;
DFS(,); for(int i=; i<cutt.size(); i++)
{
int a=cutt[i].first;
int b=cutt[i].second;
du[find(a)]++;
du[find(b)]++;
}
int ans=;
for(int i=; i<=f; i++)
if(du[i]==) ans++;
/*
如果叶子数为偶数,可以采用互缠。
比如叶子顺序1234可以1-3,2-4。
注意奇数个叶子的情况。
*/
return ((ans+)/);
} int main()
{
freopen("input.txt", "r", stdin);
int f, r, a, b, j=;
char s[N];
while(cin>>f>>r)
{
for(int i=; i<=f; i++) vect[i].clear();
while(r--)
{
scanf("%d%d", &a, &b);
vect[a].push_back(b);
vect[b].push_back(a);
}
printf("%d\n",cal_bcc(f));
}
return ;
}

AC代码

POJ 3177 Redundant Paths (桥,边双连通分量,有重边)的更多相关文章

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

    [题目链接] http://poj.org/problem?id=3177 [题目大意] 给出一张图,问增加几条边,使得整张图构成双连通分量 [题解] 首先我们对图进行双连通分量缩点, 那么问题就转化 ...

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

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

  3. POJ - 3177 Redundant Paths (边双连通缩点)

    题意:在一张图中最少可以添加几条边,使其中任意两点间都有两条不重复的路径(路径中任意一条边都不同). 分析:问题就是最少添加几条边,使其成为边双连通图.可以先将图中所有边双连通分量缩点,之后得到的就是 ...

  4. POJ 3177 Redundant Paths 无向图边双联通基础题

    题意: 给一个无向图,保证任意两个点之间有两条完全不相同的路径 求至少加多少边才能实现 题解: 得先学会一波tarjan无向图 桥的定义是:删除这条边之后该图不联通 一条无向边(u,v)是桥,当且仅当 ...

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

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

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

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

  7. poj 3177 Redundant Paths(边双连通分量+缩点)

    链接:http://poj.org/problem?id=3177 题意:有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新建多少条路,使得任 ...

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

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

  9. 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 ...

随机推荐

  1. HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?

    // test02.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...

  2. oracle——merge

      一.概述 使用merge声明从一个或者更多个表或视图中筛选记录,以用来更新或者插入到一个表或视图中.你可以指定条件以决定是执行update操作还是insert操作到目标表或视图中. 这个声明是一个 ...

  3. dll 入口函数

    http://support.microsoft.com/kb/815065/zh-cn // SampleDLL.cpp // #include "stdafx.h" #defi ...

  4. tomcat 解析(五)-Tomcat的核心组成和启动过程

    声明:源码版本为Tomcat 6.0.35 前面的文章中介绍了Tomcat的基本配置,每个配置项也基本上对应了Tomcat的组件结构,如果要用一张图来形象展现一下Tomcat组成的话,整个Tomcat ...

  5. java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@450b2f48 异常处理

    晕死的错误,改了半天也没想到是这样的原因,基础正要呀... 先看一下警告信息: 07-07 08:32:19.540: WARN/WindowManager(74): Failed looking u ...

  6. mMathf -》 Unity3d通用脚本

    public class mMathf { /// <summary> /// 辗转 相除法 求 最大公约数 /// a / b = k /// a % b = r /// 原理 gcd( ...

  7. POJ 1330 Nearest Common Ancestors(求最近的公共祖先)

    题意:给出一棵树,再给出两个节点a.b,求离它们最近的公共祖先.方法一: 先用vector存储某节点的子节点,fa数组存储某节点的父节点,最后找出fa[root]=0的根节点root.      之后 ...

  8. IOS委托设计模式(摘自IOS开发指南)

  9. hdu1031 Design T-Shirt

    http://acm.hdu.edu.cn/showproblem.php?pid=1031 #include<iostream> #include<stdio.h> #inc ...

  10. 表单插件——form

    表单插件——form 通过表单form插件,调用ajaxForm()方法,实现ajax方式向服务器提交表单数据,并通过方法中的options对象获取服务器返回数据,调用格式如下: $(form). a ...