zoukankan      html  css  js  c++  java
  • HDU 3394 Railway —— (点双联通,记录块信息)

      这题是比较模板的找点双联通并记录的题目。

      题意大概是:一个公园有n个景点,1.所有游客都是绕环旅游的,找出所有不在环内的路的条数;2.如果两个环中有重复的边,那么这些边是冲突的,问冲突的边的总数。

      分析:1.即桥的条数;2.找出点双联通分量,在他们内部找重复的边,或者换句话说,找出所有点双联通分量,边数大于点数的,这些边都是冲突的

      那么,什么是点双联通分量呢,就是任意两点都有两条或以上的路径,这些路径的点除了这两点以外,都不相同,或者说,内部无割点,像数字8的形状就不是,8是边双联通;或者再换句话说,任意两边都在一个简单环

      而边双联通图呢,是任意一边都在一个简单环。或者说,所有边都不是桥

      搞清楚这两点就可以了。然后代码都是模板的问题,代码如下:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #include <vector>
      5 #include <stack>
      6 #include <set>
      7 using namespace std;
      8 typedef pair<int,int> pii;
      9 
     10 int n,m;
     11 vector<int> G[10000+5];
     12 int dfn[10000+5],low[10000+5];
     13 int dfs_clock,cnt_qiao,cnt_scc;
     14 vector<pii> block[10000+5];
     15 int vis[10000+5];
     16 stack<pii> S;
     17 
     18 void init()
     19 {
     20     for(int i=0;i<n;i++) G[i].clear();
     21     memset(dfn,0,sizeof(dfn));
     22     dfs_clock=0;
     23     cnt_qiao=0;
     24     cnt_scc=0;
     25     for(int i=0;i<n;i++) block[i].clear();
     26 }
     27 
     28 void dfs(int u,int fa)
     29 {
     30     dfn[u]=low[u]=++dfs_clock;
     31     for(int i=0;i<G[u].size();i++)
     32     {
     33         int v = G[u][i];
     34         if(v==fa) continue;
     35         //S.push(pii(u,v));
     36         //不能在这里push边,不然会出现重边
     37 
     38         if(!dfn[v])   //这是从父到子的访问顺序,只有这个顺序才能判断是不是割点或者桥
     39         {
     40             S.push(pii(u,v));
     41             dfs(v,u);
     42             low[u]=min(low[u],low[v]);
     43 
     44             if(dfn[u]<=low[v]) //这一点是准割点(在根处不成立)
     45             {
     46                 for(;;)
     47                 {
     48                     pii t = S.top();S.pop();
     49                     block[cnt_scc].push_back(t);
     50                     if(t.first==u && t.second==v) break;
     51                 }
     52                 cnt_scc++;
     53             }
     54             if(dfn[u]<low[v]) cnt_qiao++;
     55         }
     56         else if(dfn[v]<dfn[u])    //这是子到父的访问顺序,即反向边
     57         {
     58             S.push(pii(u,v));
     59             low[u]=min(low[u],dfn[v]);
     60         }
     61     }
     62 }
     63 
     64 void solve()
     65 {
     66     for(int i=0;i<n;i++) if(!dfn[i]) dfs(i,-1);
     67 
     68     int cnt=0;
     69 
     70     for(int i=0;i<cnt_scc;i++)
     71     {
     72         memset(vis,0,sizeof(vis));
     73         int cnt_edge = block[i].size();
     74         int cnt_point=0;
     75         for(int j=0;j<block[i].size();j++)
     76         {
     77             pii t = block[i][j];
     78             int u = t.first,v = t.second;
     79             if(!vis[u]) vis[u]=1,cnt_point++;
     80             if(!vis[v]) vis[v]=1,cnt_point++;
     81         }
     82 
     83         if(cnt_point<cnt_edge)
     84         {
     85             cnt+=cnt_edge;
     86         }
     87     }
     88 
     89     printf("%d %d
    ",cnt_qiao,cnt);
     90 }
     91 
     92 int main()
     93 {
     94     while(scanf("%d%d",&n,&m)==2)
     95     {
     96         if(n==0 && m==0) break;
     97         init();
     98 
     99         for(int i=1;i<=m;i++)
    100         {
    101             int u,v;
    102             scanf("%d%d",&u,&v);
    103             G[u].push_back(v);
    104             G[v].push_back(u);
    105         }
    106 
    107         solve();
    108     }
    109     return 0;
    110 }
  • 相关阅读:
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Linux下的iwpriv(iwlist、iwconfig)的简单应用
    OCX控件的注册卸载,以及判断是否注册
    .OCX、.dll文件注册命令Regsvr32的使用
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5633558.html
Copyright © 2011-2022 走看看