hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径
题意如上,含有重边(重边的话,俩个点就能够构成了边双连通)。
先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少。这里学习了树的直径求法:第一次选随意起点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 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径的更多相关文章
- hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径
题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v ...
- HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...
- HDU-4612 Warm up,tarjan求桥缩点再求树的直径!注意重边
Warm up 虽然网上题解这么多,感觉写下来并不是跟别人竞争访问量的,而是证明自己从前努力过,以后回头复习参考! 题意:n个点由m条无向边连接,求加一条边后桥的最少数量. 思路:如标题,tarjan ...
- HDU4612+Tarjan缩点+BFS求树的直径
tarjan+缩点+树的直径题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少.先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. /* tarjan ...
- hdoj3534(树形dp,求树的直径的条数)
题目链接:https://vjudge.net/problem/HDU-3534 题意:给出一棵树,求树上最长距离(直径),以及这样的距离的条数. 思路:如果只求直径,用两次dfs即可.但是现在要求最 ...
- HDU4612 Warm up 边双(重边)缩点+树的直径
题意:一个连通无向图,问你增加一条边后,让原图桥边最少 分析:先边双缩点,因为连通,所以消环变树,每一个树边都是桥,现在让你增加一条边,让桥变少(即形成环) 所以我们选择一条树上最长的路径,连接两端, ...
- hdu-4612(无向图缩点+树的直径)
题意:给你n个点和m条边的无向图,问你如果多加一条边的话,那么这个图最少的桥是什么 解题思路:无向图缩点和树的直径,用并查集缩点: #include<iostream> #include& ...
- 无向图Tarjan&&求树直径
Tarjan可以用来求无向图的割点和割边 割边:\(dfn[u]<low[v]\) 割点:\(low[v]>=dfn[u]\) 求树的直径 做法1:BFS 从任意一个点开始BFS,然后找到 ...
- [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), ...
随机推荐
- LeetCode OJ-- Sudoku Solver ***
https://oj.leetcode.com/problems/sudoku-solver/ 九宫格数独问题. 一行上为1 2 3 到9 一列上为1 2 3 到9 每个小的3*3格子为 1 2 3 ...
- Android Studio插件Gsonformat的安装和使用
在开发中,我们获得服务端的json数据后要建立自己的bean,但是一条一条写相当麻烦,使用了GsonFormat插件,用起来非常方便. 安装 方法1: 1.Android studio File-&g ...
- Codeforces 761D Dasha and Very Difficult Problem(贪心)
题目链接 Dasha and Very Difficult Problem 求出ci的取值范围,按ci排名从小到大贪心即可. 需要注意的是,当当前的ci不满足在这个取值范围内的时候,判为无解. #in ...
- Aria2使用教程
Aria2 是一个轻量级多协议和多源命令行下载实用工具.它支持 HTTP / HTTPS, FTP, SFTP, bt 和 Metalink.通过内置 Aria2 可以操作 json - rpc 和 ...
- SQLITE3 --详解
由于我主要负责我们小组项目数据库模块的部分所以这几天都一直在研究在iphone中最为常用的一个简单数据库sqlite,自己也搜集很多资料,因此在 这里总结一下这几天的学习成果: Sqlite 操作简明 ...
- 脚本命令加载外部配置文件夹conf
加载log4j配置文件 Log4iConfigurer类 public class Log4iConfigurer { private static boolean INITIALIZED = fal ...
- 服务器启动之后运行脚本在/etc/rc.d/rc.local中配置
服务器启动之后运行脚本在/etc/rc.d/rc.local中配置 # ! /bin/sh # 启动svn /usr/bin/svnserve -d -r /var/svnroot/
- VC++动态链接库(DLL)编程深入浅出(二)
好,让我们正式进入动态链接库的世界,先来看看最一般的DLL,即非MFC DLL 上节给大家介绍了静态链接库与库的调试与查看,本节主要介绍非MFC DLL. 4.非MFC DLL 4.1一个简单的DLL ...
- Android 使用意图播放本地视频
Android播放视频的方式有三种: 一.使用意图播放,调用本地安装的播放器,选择一个进行播放. 二.使用VideoView播放(VideoView事实上是对MediaPlayer的封装,使用起来非常 ...
- 微信小程序-关于日期选择器(input)
小程序并没有input带有日期组件(只有picker组件带日期),要不自创,要不就用picker把选中的值放入input当中 wxml js 因为会触发input,所以禁用它就可以了