zoukankan      html  css  js  c++  java
  • kuangbin专题 专题九 连通图 Warm up HDU

    题目链接:https://vjudge.net/problem/HDU-4612

    题目:一个大地图,给定若干个连通图,每个连通图中有若干个桥,你可以在任意某个连通图的

    任意两个点添加一条边,问,添加一条边后,大地图中最少剩下几个桥。

    思路:tarjan缩点,重构图,对每个新图跑两次dfs求出树的直径,取所有新图的直径max,

    答案就是  大地图总桥数 - max(树的直径)。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <vector>
      6 using namespace std;
      7 #define pb push_back
      8 
      9 const int N = (int)2e5+10;
     10 const int M = (int)1e6+10;
     11 int n,m,bridge,tot,tim,top,scc;
     12 int head[N],dfn[N],low[N],s[N],scc_no[N],vis[N];
     13 struct node{
     14     int to;
     15     int nxt;
     16 }e[M << 1];
     17 vector<int> g[N];//新图
     18 vector<int> poi;//存单个连通图包含的点
     19 
     20 void init(){
     21     for(int i = 0; i <= n; ++i){
     22         head[i] = -1;
     23         dfn[i] = 0;
     24         g[i].clear();
     25     }
     26     bridge = tot = tim = top = scc = 0;
     27 }
     28 
     29 inline void add(int u,int v){
     30     e[tot].to = v;
     31     e[tot].nxt = head[u];
     32     head[u] = tot++;
     33 }
     34 
     35 //tarjan缩点
     36 void tarjan(int now,int pre){
     37     poi.pb(now);//存下这个连通图包含的点
     38     dfn[now] = low[now] = ++tim;
     39     s[top++] = now;
     40     int to,pre_cnt = 0;
     41     for(int o = head[now]; ~o; o = e[o].nxt){
     42         to = e[o].to;
     43         if(to == pre && pre_cnt == 0) { pre_cnt = 1; continue; }
     44         if(!dfn[to]){
     45             tarjan(to,now);
     46             low[now] = min(low[now],low[to]);
     47             if(dfn[now] < low[to]) ++bridge;
     48         }else low[now] = min(low[now],dfn[to]);
     49     }
     50 
     51     if(dfn[now] == low[now]){
     52         int x;
     53         ++scc;
     54         do{
     55             x = s[--top];
     56             scc_no[x] = scc;
     57         }while(now != x);
     58     }
     59 }
     60 
     61 //对poi中的那些点新建一个图
     62 void rebuild(){
     63     int to,now;
     64     for(int i = 0; i < (int)poi.size(); ++i){
     65         now = poi[i];
     66         for(int o = head[now]; ~o; o = e[o].nxt){
     67            to = e[o].to;
     68            if(scc_no[now] == scc_no[to]) continue;
     69            g[scc_no[now]].pb(scc_no[to]);  g[scc_no[to]].pb(scc_no[now]);
     70         }
     71     }
     72 }
     73 
     74 void dfs(int now,int pre,int deep){
     75     vis[now] = deep;
     76     int to;
     77     for(int i = 0; i < (int)g[now].size(); ++i){
     78         to = g[now][i];
     79         if(to == pre || to == now || vis[to]) continue;
     80         dfs(to,now,deep+1);
     81     }
     82 }
     83 
     84 void test01(){
     85     for(int i = 1; i <= n; ++i)
     86         printf("%d 属于scc = %d
    ",i,scc_no[i]);
     87 }
     88 
     89 
     90 void solve(){
     91 
     92     int max_deep = 0,_deep = 0;
     93     int u;
     94     for(int i = 1; i <= n; ++i){
     95         if(!dfn[i]){
     96             poi.clear();//清空上个连通图中的点
     97             tarjan(i,i);
     98             rebuild();//poi中的点重建图
     99             dfs(poi[0],poi[0],1);
    100             _deep = 0;
    101             for(int i = 0; i < poi.size(); ++i){
    102                 if(_deep < vis[poi[i]]){ _deep = vis[poi[i]]; u = poi[i]; }
    103                 vis[poi[i]] = 0; //这里别忘了初始化  不然下次dfs会出错
    104             }
    105             dfs(u,u,1);
    106             for(int i = 0; i < poi.size(); ++i){
    107                 _deep = max(_deep,vis[poi[i]]);
    108                 vis[poi[i]] = 0;//这里别忘了初始化  不然下组数据的dfs会出错
    109             }
    110             max_deep = max(max_deep,_deep);//对每个连通图跑两次dfs求树的直径,取max
    111         }
    112     }
    113 //    cout << bridge << "   " << max_deep << endl;
    114     printf("%d
    ",bridge - max_deep +1);
    115 }
    116 
    117 int main(){
    118 
    119     int u,v;
    120     while(~scanf("%d%d",&n,&m) && (n+m)){
    121         init();
    122         for(int i = 0; i < m; ++i){
    123             scanf("%d%d",&u,&v);
    124             add(u,v); add(v,u);
    125         }
    126         solve();
    127     }
    128 
    129 
    130     return 0;
    131 }

    4 4
    1 2
    1 3
    1 4
    2 3

    11 12
    1 2
    1 3
    3 2
    3 4
    4 5
    4 6
    6 7
    7 8
    7 9
    8 9
    8 11
    9 10

    6 7
    1 2
    1 3
    2 3
    3 4
    4 5
    4 6
    5 6


    8 6
    1 2
    1 3
    1 4
    1 5
    7 6
    6 8

  • 相关阅读:
    设计模式
    包装类
    php 闭包的理解
    is_null empty isset等的判定
    PHP基础一 $this ,static 和 self的区别
    lumen安装踩过得坑
    composer的使用和安装
    使用submine来写c++
    php 和 thinkphp中的常量一览
    路径问题 ./ / ../ 空 的区别
  • 原文地址:https://www.cnblogs.com/SSummerZzz/p/12201771.html
Copyright © 2011-2022 走看看