poj 3177 Redundant Paths(边双连通分量+缩点)
链接: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(边双连通分量+缩点)的更多相关文章
- POJ 3177 Redundant Paths (边双连通+缩点)
<题目链接> <转载于 >>> > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...
- POJ 3177 Redundant Paths 边双(重边)缩点
分析:边双缩点后,消环变树,然后答案就是所有叶子结点(即度为1的点)相连,为(sum+1)/2; 注:此题有坑,踩踩更健康,普通边双缩短默认没有无向图没有重边,但是这道题是有的 我们看,low数组是我 ...
- POJ 3352 Road Construction ; POJ 3177 Redundant Paths (双联通)
这两题好像是一样的,就是3177要去掉重边. 但是为什么要去重边呢??????我认为如果有重边的话,应该也要考虑在内才是. 这两题我用了求割边,在去掉割边,用DFS缩点. 有大神说用Tarjan,不过 ...
- tarjan算法求桥双连通分量 POJ 3177 Redundant Paths
POJ 3177 Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12598 Accept ...
- POJ 3177 Redundant Paths POJ 3352 Road Construction(双连接)
POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的.一份代码能交.给定一个连通无向图,问加几条边能使得图变成一个双连通图 ...
- POJ 3177 Redundant Paths(边双连通分量)
[题目链接] http://poj.org/problem?id=3177 [题目大意] 给出一张图,问增加几条边,使得整张图构成双连通分量 [题解] 首先我们对图进行双连通分量缩点, 那么问题就转化 ...
- POJ - 3177 Redundant Paths (边双连通缩点)
题意:在一张图中最少可以添加几条边,使其中任意两点间都有两条不重复的路径(路径中任意一条边都不同). 分析:问题就是最少添加几条边,使其成为边双连通图.可以先将图中所有边双连通分量缩点,之后得到的就是 ...
- [双连通分量] POJ 3177 Redundant Paths
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13712 Accepted: 5821 ...
- poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11047 Accepted: 4725 ...
随机推荐
- Ubuntu中创建Python虚拟环境
创建虚拟环境对于Python开发来说是非常重要的,那么该如何创建虚拟环境呢? 1.安装virtulenv工具和管理包 sudo apt-get install python3-virtulenv 或 ...
- go标准库的学习-mime
参考:https://studygolang.com/pkgdoc 导入方法: import "mime" mime实现了MIME的部分规定. 什么是MIME: MIME(Mult ...
- Spark运行时错误与解决
Spark java.io.IOException: Filesystem closed partition数量太小,读取数据后进行repartition重新分片再处理. Spark Streami ...
- LeetCode112:Path Sum
正常写法 bool HasPathSum(TreeNode root, int sum) { bool ret=false; if(root==null)return false; if(root.l ...
- 【php增删改查实例】第十六节 - 用户新增
6.1工具栏 <div id="toolbar"> <a href="javascript:openDialog()" class=" ...
- FSMC的个人理解
个人理解: FSMC相当于外部设备存储器地址在FSMC对应存储地址中的映射,通过在FSMC的存储地址中写数据,就能通过FSMC的地址线和数据线,将地址和数据写到外部设备存储器地址中.所以,程序中,需要 ...
- 扫描shader
游戏中经常需要制作出白光扫描的效果,这道光在透明区域不会显示.如果用图片叠加可能透明区域不太好处理,这里可通过shader实现. Shader "Custom/LogoShader" ...
- @Vue/Cli 3 关于 render 空的处理
问题场景 vue-cli 3 在打包部署时候会出现 dist folder not working "Uncaught TypeError: Cannot set property 'ren ...
- .net core实践系列之短信服务-Sikiro.SMS.Bus服务的实现
前言 前两篇<.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现>.<.net core实践系列之短信服务-Api的SDK的实现与测试>分别讲解了AP ...
- 值类型和引用类型的区别,struct和class的区别
C#值类型和引用类型 1.简单比较 值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中. 值类型(value type):byte,short,int,long,floa ...