题意如上,含有重边(重边的话,俩个点就能够构成了边双连通)。

先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少。这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v(level最深)该点必定是树的直径的一个端点,,再从该点出发,bfs,到最深的一点。该点深度就是直径。

(证明:先如果u。是直径上一点,S,T是直径的端点。设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v;若u不是直径上一点。设u到直径上的一点为x。同理易证。

最后 缩点后树的边-直径就可以。

再说说这次,哎。先是爆栈,没有在C++申请空间。。。 无向图的tarjian太不熟练了。非常久没敲了。

。。。

注意点:无向图求边双连通,缩点,能够这样:

法1:必需用前向星来保存边,然后标记訪问边(同一时候标记反向边)的方法来处理。这样,重边的话。就在字自然在一个边通分量中了。(要求边数能够用数组存下),这样不用。=-father来推断。

法2,重边视为单边(仅仅有俩个点不连通),不标记边,多一个參数father。在返祖边更新我的时候,加推断!=father。

#pragma comment(linker, "/STACK:10240000000000,10240000000000")        //申请空间
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<stack>
using namespace std;
const int maxv=300010;
int dfn[maxv];int low[maxv];int visited[maxv];
int ins[maxv];stack<int>sta;int scc[maxv];
int times=0;int block=0;
int n,m;
int minn(int a,int b)
{
if(a<=b)return a;
return b;
}
int nume=0;int e[2000500][2];int head[maxv];
void inline adde(int i,int j) //原图
{
e[nume][0]=j;e[nume][1]=head[i];head[i]=nume++;
e[nume][0]=i;e[nume][1]=head[j];head[j]=nume++;
}
int nume2=0;int newg[2000500][2];int head2[maxv];
void inline adde2(int i,int j) //新图
{
newg[nume2][0]=j;newg[nume2][1]=head2[i];head2[i]=nume2++;
newg[nume2][0]=i;newg[nume2][1]=head2[j];head2[j]=nume2++;
}
bool marke[2001000]; //标记边的訪问
void tarjan(int u)
{
dfn[u]=low[u]=++times;
ins[u]=1;
sta.push(u);
for(int i=head[u];i!=-1;i=e[i][1])
{
int child=e[i][0];
if(marke[i])continue; //注意放在这里,否则以下的会更新。起不了作用
if(visited[child]==0)
{
visited[child]=1;
marke[i]=marke[i^1]=1; //标记双向
tarjan(child);
low[u]=minn(low[u],low[child]);
}
else if(ins[child])
{
low[u]=minn(dfn[child],low[u]);
}
}
if(low[u]==dfn[u]) //同一个边双连通
{
block++;
int cur;
do
{
cur=sta.top();
ins[cur]=0;
sta.pop();
scc[cur]=block;
}while(cur!=u);
}
}
void rebuild()
{
for(int i=1;i<=n;i++) //遍历全部边。来又一次建图,若在同一个边双连通中,则有边。
{
for(int j=head[i];j!=-1;j=e[j][1])
{
int ch=e[j][0];
if(scc[i]!=scc[ch])
adde2(scc[i],scc[ch]);
}
}
}
int lev[maxv];
void bfsgetlev(int ss) //BFS分层
{
memset(lev,0,sizeof(lev));
memset(visited,0,sizeof(visited));
queue<int>q;
q.push(ss);
visited[ss]=1;
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=head2[cur];i!=-1;i=newg[i][1])
{
int vv=newg[i][0];
if(!visited[vv])
{
lev[vv]=lev[cur]+1;
q.push(vv);
visited[vv]=1;
}
}
}
return ;
}
void init()
{ block=times=0;nume=0;nume2=0;
memset(marke,0,sizeof(marke));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(visited,0,sizeof(visited));
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2)); }
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
{
init();
int a,b;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
adde(a,b);
}
visited[1]=1;
tarjan(1);
rebuild();
int ans=0;
bfsgetlev(1);
int froms=0;
int maxx=-1;
for(int i=1;i<=block;i++)
{
if(lev[i]>maxx)
{
maxx=lev[i];
froms=i;
}
}
bfsgetlev(froms); //最远点(直直径的一个端点)
for(int i=1;i<=block;i++)
{
if(lev[i]>maxx)
{
maxx=lev[i];
}
}
ans=block-1-maxx;
printf("%d\n",ans); }
return 0;
}

hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径的更多相关文章

  1. hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

    题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v ...

  2. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  3. HDU-4612 Warm up,tarjan求桥缩点再求树的直径!注意重边

    Warm up 虽然网上题解这么多,感觉写下来并不是跟别人竞争访问量的,而是证明自己从前努力过,以后回头复习参考! 题意:n个点由m条无向边连接,求加一条边后桥的最少数量. 思路:如标题,tarjan ...

  4. HDU4612+Tarjan缩点+BFS求树的直径

    tarjan+缩点+树的直径题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少.先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. /* tarjan ...

  5. hdoj3534(树形dp,求树的直径的条数)

    题目链接:https://vjudge.net/problem/HDU-3534 题意:给出一棵树,求树上最长距离(直径),以及这样的距离的条数. 思路:如果只求直径,用两次dfs即可.但是现在要求最 ...

  6. HDU4612 Warm up 边双(重边)缩点+树的直径

    题意:一个连通无向图,问你增加一条边后,让原图桥边最少 分析:先边双缩点,因为连通,所以消环变树,每一个树边都是桥,现在让你增加一条边,让桥变少(即形成环) 所以我们选择一条树上最长的路径,连接两端, ...

  7. hdu-4612(无向图缩点+树的直径)

    题意:给你n个点和m条边的无向图,问你如果多加一条边的话,那么这个图最少的桥是什么 解题思路:无向图缩点和树的直径,用并查集缩点: #include<iostream> #include& ...

  8. 无向图Tarjan&&求树直径

    Tarjan可以用来求无向图的割点和割边 割边:\(dfn[u]<low[v]\) 割点:\(low[v]>=dfn[u]\) 求树的直径 做法1:BFS 从任意一个点开始BFS,然后找到 ...

  9. [LeetCode] Number of Connected Components in an Undirected Graph 无向图中的连通区域的个数

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

随机推荐

  1. spingboot 邮件模板发送;

    <!-- 邮件start --><dependency> <groupId>javax.mail</groupId> <artifactId> ...

  2. linux创建和查看用户命令

    1.创建一个叫做hadoop的用户,用户的目录是/home/hadoop useradd -d /home/hadoop hadoop 2.输入密码 passwd hadoop 3.删除用户 user ...

  3. 搜狗拼音输入法LINUX版安装

    搜狗拼音输入法LINUX版官方下载: http://pinyin.sogou.com/linux/?r=pinyin 一.添加fcitx的nightlyPPA 在终端中输入: sudo add-apt ...

  4. (6)centos安装和解压

    一.rpm包安装方式步骤:1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录:2.打开一个终端,su -成root用户:3.cd soft.version.rpm所在的目录 ...

  5. Goodbye 2017 B

    [题意]: 鲍勃编程一个机器人在2d迷宫中导航.迷宫有一些障碍.空单元格用'.'表示,其中障碍物用'#'表示.迷宫中有一个机器人.它的起始位置用字符“S”表示.这个位置没有任何障碍.迷宫中也有一个出口 ...

  6. Swoole MySQL 连接池的实现

    目录 概述 代码 扩展 小结 概述 这是关于 Swoole 入门学习的第八篇文章:Swoole MySQL 连接池的实现. 第七篇:Swoole RPC 的实现 第六篇:Swoole 整合成一个小框架 ...

  7. 浅谈.Net异步编程的前世今生----EAP篇

    前言 在上一篇博文中,我们提到了APM模型实现异步编程的模式,通过使用APM模型,可以简化.Net中编写异步程序的方式,但APM模型本身依然存在一些缺点,如无法得知操作进度,不能取消异步操作等. 针对 ...

  8. Android学习--持久化(一) 文件存储

    持久化之   文件存储 这里把Android持久化全都整理一下,这一篇文章先简单的说一下文件的存储,通过下面一个简单的Demo,理解一下这个文件存储,先说说下面Demo的思路: 1.创建EditTex ...

  9. Android Studio 中.android 文件夹移动默认位置

    转自 开发工具打造: .android 文件夹移动默认位置 .android 文件夹是用来存放 avd 模拟器文件的文件夹. 因为默认是 C盘 的. 占用空间比较大.很不爽 将它移动到其它盘其实很简单 ...

  10. CBIntrospector俗称:内部检查工具

    Download View Introspector   (CBIntrospector)内部检查工具是IOS和IOS模拟器的小工具集,帮助在调试的UIKit类的用户界面,它尤其有用于动态UI布局创建 ...