<题目链接>

题目大意:
给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量。

解题分析:

首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点都是一个边双连通分量,树上的每条边都是桥,现在需要挑出两个点,将它们直接相连,这样它们原始路径上所有的桥因为形成了环而全部消失,因此为了使剩下的桥最少,我们需要找到路径上桥最多的两点,又由于缩点后,树的每条边都是桥,所以这里就转化为树上距离两点的最远距离,也就是求树的直径。

下面Tarjan的时候需要注意的是,vis记录的是访问过边的编号不是节点的编号。

 #include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 #include <queue>
 using namespace std;
 #define mem(a,b) memset(a,b,sizeof(a))
 typedef pair<int, int> pll;
 ;
 ;
 int num, num1, top, cnum,maxdis, pos,cnt;
 int head[N], head1[N], dis[N],instk[N], stk[N], dfn[N], low[N], belong[N];
 ];
 struct Edge{
     int to, next;
 }e[M<<], e1[M<<];

 void add(int u, int v) {
     e[num].to = v, e[num].next = head[u], head[u] = num++;
 }
 void add1(int u, int v) {
     e1[num1].to = v, e1[num1].next = head1[u], head1[u] = num1++;
 }
 void init() {
     num = num1 = cnt = cnum = top = ;
     mem(head,-),mem(head1,-),mem(belong,),mem(instk,);
     mem(vis,),mem(stk,),mem(dfn,),mem(low,),mem(dis,);
 }
 pll edge[M];
 void tarjan(int u){
     dfn[u] = low[u] = ++cnt;
     instk[u] = ;
     stk[++top] = u;
     for(int i = head[u]; ~i; i = e[i].next) {
         int v = e[i].to;
         if(vis[i])continue;
         vis[i] = vis[i^] = ;    //将正、反两边全部标记
         if(!dfn[v]) {
             tarjan(v);
             low[u] = min(low[u], low[v]);
         } else if(instk[v]) {
             low[u] = min(low[u], dfn[v]);
         }
     }
     if(low[u] == dfn[u]) {
         ++cnum;      //cnum为边双连通分量的数量
         int v;
         do{
             v = stk[top--];
             instk[v] = ;
             belong[v] = cnum;     //将该连通块染色
         } while(v != u);
     }
 }
 void bfs(int u){
     queue <int> q;
     q.push(u);
     dis[u] = ;
     mem(vis,);
     vis[u] = ;
     maxdis = , pos = u;
     while(!q.empty()) {
         int u = q.front(); q.pop();
         for(int i = head1[u]; ~i; i = e1[i].next) {
             int v = e1[i].to;
             if(vis[v])continue;
             vis[v] = ;
             dis[v] = dis[u]+;
             if(dis[v]>maxdis) {     //更新树上的最远距离
                 maxdis = dis[v];
                 pos = v;     //并且记录下该点
             }
             q.push(v);
         }
     }
 }
 int main()
 {
     int n, m, x, y;
     while(scanf("%d%d",&n,&m)!=EOF,n||m){
         init();
         ; i<m; i++) {
             scanf("%d%d", &x, &y);
             edge[i].first = x, edge[i].second = y;  //记录下所有的边,用结构体记录也可以
             add(x, y),add(y, x);
         }
         tarjan();
         ;
         ; i<m; i++){    //将缩点后的所有点建图,跑BFS,求树的直径
             int x = edge[i].first, y = edge[i].second;
             if(belong[x]!=belong[y]) {
                 add1(belong[x], belong[y]);
                 add1(belong[y], belong[x]);
                 edgenum++;     //桥的数量+1
             }
         }
         bfs(belong[]);
         bfs(pos);     //求出此时树的直径,即一条路径上所含的最多桥的数量
         int ans = edgenum-maxdis;
         printf("%d\n", ans);
     }
 }

2018-11-07

HDU 4612 Warm up (边双连通分量+缩点+树的直径)的更多相关文章

  1. HDU 4612 Warm up(双连通分量缩点+求树的直径)

    思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v, ...

  2. hdu4612 Warm up[边双连通分量缩点+树的直径]

    给你一个连通图,你可以任意加一条边,最小化桥的数目. 添加一条边,发现在边双内是不会减少桥的.只有在边双与边双之间加边才有效.于是,跑一遍边双并缩点,然后就变成一棵树,这样要加一条非树边,路径上的点( ...

  3. HDU 4612 Warm up (边双连通分量+DP最长链)

    [题意]给定一个无向图,问在允许加一条边的情况下,最少的桥的个数 [思路]对图做一遍Tarjan找出桥,把双连通分量缩成一个点,这样原图就成了一棵树,树的每条边都是桥.然后在树中求最长链,这样在两端点 ...

  4. Gym - 100676H H. Capital City (边双连通分量缩点+树的直径)

    https://vjudge.net/problem/Gym-100676H 题意: 给出一个n个城市,城市之间有距离为w的边,现在要选一个中心城市,使得该城市到其余城市的最大距离最短.如果有一些城市 ...

  5. hdoj 4612 Warm up【双连通分量求桥&&缩点建新图求树的直径】

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

  6. hdu 4612 Warm up 双连通缩点+树的直径

    首先双连通缩点建立新图(顺带求原图的总的桥数,事实上因为原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首 ...

  7. HDU-4612 Warm up 边双连通分量+缩点+最长链

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 简单图论题,先求图的边双连通分量,注意,此题有重边(admin还逗比的说没有重边),在用targ ...

  8. hdu4612(双连通缩点+树的直径)

    传送门:Warm up 题意:询问如何加一条边,使得剩下的桥的数目最少,输出数目. 分析:tarjan缩点后,重新建图得到一棵树,树上所有边都为桥,那么找出树的直径两个端点连上,必定减少的桥数量最多, ...

  9. HDU 4612 Warm up(2013多校2 1002 双连通分量)

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

随机推荐

  1. Windows下安装Confluence并破解汉化

    注:本文来源于<Windows下安装Confluence并破解汉化> 一.事前准备 1:JDK下载并安装:jdk-6u45-windows-i586.exe 2:MySQL JDBC连接驱 ...

  2. SQL*Plus工具

    或者

  3. Confluence 6 home 目录

    Confluence Home 目录是存储 Confluence 信息,查找索引,页面附件的地方.其实 Home 目录也可以定义为数据目录. 找到 Home 目录 Confluence 的 home ...

  4. 放一点百度来的,常见的windowserror

    0操作成功完成.1功能错误.2系统找不到指定的文件.3系统找不到指定的路径.4系统无法打开文件.5拒绝访问.6句柄无效.7存储控制块被损坏.8存储空间不足,无法处理此命令.9存储控制块地址无效.10环 ...

  5. PHP array_combine()

    // 需要替换 key 的数组 $arr_old = array( '0' => array('id' => 1, 'name' => 'Carroll'), '1' => a ...

  6. 重建控制文件报错 ORA-01503 ORA-01192

    1. 错误信息 ORA-: CREATE CONTROLFILE failed ORA-: must have at least one enabled thread 2. 重建脚本 CREATE C ...

  7. 最短路径问题---Dijkstra算法详解

    侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...

  8. SQL查询数据并插入新表

    SQL查询数据并插入新表 --如果接受数据导入的表已经存在 insert into 表 select * from tablename --如果导入数据并生成表 select * into 表 fro ...

  9. windows server 2012 R2 远程桌面授权模式尚未配置

    windows server 2012 R2 远程桌面授权模式尚未配置,远程桌面服务将在120天内停止工作.如何破解这个宽限期,目前企业7位协议号码均不包含2012 R2以上授权. 那么只能蛋疼的“破 ...

  10. xcode svn commit is not under version control 和 git常用指令

    使用Xcode提交一个第三方库时,由于包含资源文件,总是提交不了,提示报错:XXX commit is not under version control (1) 网上查了下,得知 xcode对于sv ...