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 ...
- python中pip添加国内镜像源后显著加速下载
python中pip添加国内镜像源后显著加速下载 更换pip源到国内镜像,很多国外的库下载非常慢,添加国内镜像后安装下载速度提升非常明显(亲测有些可以由几十kb加速到几MB) pip国内的一些镜像阿里 ...
- 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 ...
- poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11047 Accepted: 4725 ...
- 为什么不能在scrollview中直接添加一个image,然后使animation.begin()??
http://stackoverflow.com/questions/17267451/animation-cant-begin-in-scrollview-in-windows-phone 以上是我 ...
- hdoj3534(树形dp,求树的直径的条数)
题目链接:https://vjudge.net/problem/HDU-3534 题意:给出一棵树,求树上最长距离(直径),以及这样的距离的条数. 思路:如果只求直径,用两次dfs即可.但是现在要求最 ...
- HDU4612 Warm up 边双(重边)缩点+树的直径
题意:一个连通无向图,问你增加一条边后,让原图桥边最少 分析:先边双缩点,因为连通,所以消环变树,每一个树边都是桥,现在让你增加一条边,让桥变少(即形成环) 所以我们选择一条树上最长的路径,连接两端, ...
随机推荐
- C05 C语言字符串和数组
目录 数组 字符串 数组 概念 数组是有序数据的集合. 数组中的每一个元素属于同一个数据类型. 通过数组名和下标唯一确定数组中的元素. 一维数组的定义 语法格式 数据类型 数组名[常量表达式] 例 ...
- 10.字符串str的语法
1).字符串的索引以及切片 s = 'ABCDLSESRF' #索引 s1 = s[0] print(s1) #A s2 = s[2] print(s2) #C s3 = s[-1] print(s3 ...
- jpeg和jpg的区别是什么
JPG是JPEG的简写,jpg是后缀名,jpeg既可作为后缀名,又能代表文件格式:JPG——JPEG文件格式. 我们在系统自带的画图程序里保存文件,在保存类型:JPEG(*.JPG,*.JPEG,*. ...
- Broadcast BCM94322 用ubuntu修改ID
1.按这个教程的6楼做的http://bbs.pcbeta.com/viewthread-1324168-1-1.html.注意我先下载 的是ubuntu9.05版本,做U盘启动进live 模式,43 ...
- Fortran学习记录3(选择语句)
流程控制语句 if的基本用法 if-else语句块 多重判断if-elseif语句 if语句嵌套 Select case语句 Goto语句 PAUSE CONTINUE STOP 流程控制语句 if的 ...
- HDU - 4811 - Ball (思维)
题意: 给出一定数量的三种颜色的球,计算如何摆放得到值最大(有一定顺序) 有三种摆放方法 1.如果放的是第一个(桌子上原来没有),数值不变 2.如果在末尾追加一个,那么增加前面不同颜色的个数的值 3. ...
- sscanf的使用
sscanf的使用 语法 int ssanf(const char *buffer, const char *format,[argument]...); 参数 buffer 存储的数据 format ...
- 【搜索 技巧】Letter gaps
需要一定技巧的搜索题 题目描述 记得做过这样一道题 Ponder This Challenge: In the string CABACB, each letter appears exactly t ...
- Linux三剑客之sed详解(2)
一.sed 分组替换(),\1 实例:I am a oldboy teacher. 吧oldboy 提取出来 二.特殊符号&代表被替换的字符串 实例:批量替换文件名 把stu_102999_1 ...
- python爬虫(爬取图片)
python爬虫爬图片 爬虫爬校花网校花的图片 第一步 载入爬虫模块 #载入爬虫模块 import re #载入爬虫模块 import requests #载入爬虫模块 第二步 获得校花网的地址,获得 ...