链接:http://poj.org/problem?id=3177

题意:有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走。现已有m条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路。两条独立的路是指:没有公共边的路,但可以经过同一个中间顶点。

分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

缩点后,新图是一棵树,树的边就是原无向图的桥。

现在问题转化为:在树中至少添加多少条边能使图变为双连通图。

结论:添加边数=(树中度为1的节点数+1)/2

具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

其实求边双连通分量和求强连通分量差不多,每次访问点的时候将其入栈,当low[u]==dfn[u]时就说明找到了一个连通的块,则栈内的所有点都属于同一个边双连通分量,因为无向图要见反向边,所以在求边双连通分量的时候,遇到反向边跳过就行了。

网上有一种错误的做法是:因为每一个双连通分量内的点low[]值都是相同的,则dfs()时,对于一条边(u,v),只需low[u]=min(low[u],low[v]),这样就不用缩点,最后求度数的时候,再对于每条边(u,v)判断low[u]是否等于low[v],若low[u]!=low[v],则不是同一个边双连通分量,度数+1即可.....

咋看之下是正确的,但是这种做法只是考虑了每一个强连通分量重只有一个环的情况,如果有多个环,则会出错。

比如这组数据:

16 21
1 8
1 7
1 6
1 2
1 9
9 16
9 15
9 14
9 10
10 11
11 13
11 12
12 13
11 14
15 16
2 3
3 5
3 4
4 5
3 6
7 8

答案是1,上面错误的做法是0

大家自己画图慢慢研究吧。。。下面贴代码

AC代码:

 #include<cstdio>
#include<cstring>
const int N=+;
const int M=+; struct EDGE
{
int v,next;
}edge[M*];
int first[N],low[N],dfn[N],belong[N],degree[N],sta[M],instack[M];
int g,cnt,top,scc;
int min(int a,int b)
{
return a<b?a:b;
}
void AddEdge(int u,int v)
{
edge[g].v=v;
edge[g].next=first[u];
first[u]=g++;
}
void Tarjan(int u,int fa)
{
int i,v;
low[u]=dfn[u]=++cnt;
sta[++top]=u;
instack[u]=;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(i==(fa^))
continue;
if(!dfn[v])
{
Tarjan(v,i);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc++;
while()
{
v=sta[top--];
instack[v]=;
belong[v]=scc;
if(v==u)
break;
}
}
}
int main()
{
int n,m,u,v,i,j;
scanf("%d%d",&n,&m);
g=cnt=top=scc=;
memset(first,-,sizeof(first));
memset(low,,sizeof(low));
memset(dfn,,sizeof(dfn));
memset(instack,,sizeof(instack));
memset(degree,,sizeof(degree));
for(i=;i<m;i++)
{
scanf("%d%d",&u,&v);
{
AddEdge(u,v);
AddEdge(v,u);
}
}
for(i=;i<=n;i++)
if(!dfn[i])
Tarjan(,-);
for(i=;i<=n;i++)
{
for(j=first[i];j!=-;j=edge[j].next)
{
v=edge[j].v;
if(belong[i]!=belong[v])
degree[belong[i]]++;
}
}
int sum=;
for(i=;i<=n;i++)
if(degree[i]==)
sum++;
int ans=(sum+)/;
printf("%d\n",ans);
return ;
}

poj 3177 Redundant Paths(边双连通分量+缩点)的更多相关文章

  1. POJ 3177 Redundant Paths (边双连通+缩点)

    <题目链接> <转载于 >>>  > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...

  2. POJ 3177 Redundant Paths 边双(重边)缩点

    分析:边双缩点后,消环变树,然后答案就是所有叶子结点(即度为1的点)相连,为(sum+1)/2; 注:此题有坑,踩踩更健康,普通边双缩短默认没有无向图没有重边,但是这道题是有的 我们看,low数组是我 ...

  3. POJ 3352 Road Construction ; POJ 3177 Redundant Paths (双联通)

    这两题好像是一样的,就是3177要去掉重边. 但是为什么要去重边呢??????我认为如果有重边的话,应该也要考虑在内才是. 这两题我用了求割边,在去掉割边,用DFS缩点. 有大神说用Tarjan,不过 ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Ubuntu中创建Python虚拟环境

    创建虚拟环境对于Python开发来说是非常重要的,那么该如何创建虚拟环境呢? 1.安装virtulenv工具和管理包 sudo apt-get install python3-virtulenv 或 ...

  2. go标准库的学习-mime

    参考:https://studygolang.com/pkgdoc 导入方法: import "mime" mime实现了MIME的部分规定. 什么是MIME: MIME(Mult ...

  3. Spark运行时错误与解决

    Spark  java.io.IOException: Filesystem closed partition数量太小,读取数据后进行repartition重新分片再处理. Spark Streami ...

  4. LeetCode112:Path Sum

    正常写法 bool HasPathSum(TreeNode root, int sum) { bool ret=false; if(root==null)return false; if(root.l ...

  5. 【php增删改查实例】第十六节 - 用户新增

    6.1工具栏 <div id="toolbar"> <a href="javascript:openDialog()" class=" ...

  6. FSMC的个人理解

    个人理解: FSMC相当于外部设备存储器地址在FSMC对应存储地址中的映射,通过在FSMC的存储地址中写数据,就能通过FSMC的地址线和数据线,将地址和数据写到外部设备存储器地址中.所以,程序中,需要 ...

  7. 扫描shader

    游戏中经常需要制作出白光扫描的效果,这道光在透明区域不会显示.如果用图片叠加可能透明区域不太好处理,这里可通过shader实现. Shader "Custom/LogoShader" ...

  8. @Vue/Cli 3 关于 render 空的处理

    问题场景 vue-cli 3 在打包部署时候会出现 dist folder not working "Uncaught TypeError: Cannot set property 'ren ...

  9. .net core实践系列之短信服务-Sikiro.SMS.Bus服务的实现

    前言 前两篇<.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现>.<.net core实践系列之短信服务-Api的SDK的实现与测试>分别讲解了AP ...

  10. 值类型和引用类型的区别,struct和class的区别

    C#值类型和引用类型 1.简单比较 值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中. 值类型(value type):byte,short,int,long,floa ...