• poj 3694 Network (无向图的 割边 lca )


    http://poj.org/problem?id=3694


    题意:

       

    给一幅图,若干个操作,每个操作时连接两个点,对于每个操作之后的图判断图中还有几条割边
      题解 :  tarjan  + lca ;

    //将不是割边上的点缩为一个点,然后统计割边,求添加一条边之后,割边减少了多少,就是从两个点出发
    //到达他们最近的公共祖先,他们经过了几条割边,然后减去经过的割边数,就是答案,这里用到了lca
    //并查集
     

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cmath>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<set>
      7 #include<map>
      8 #include<queue>
      9 #include<vector>
     10 #include<string>
     11 #define Min(a,b) a<b?a:b
     12 #define Max(a,b) a>b?a:b
     13 #define CL(a,num) memset(a,num,sizeof(a));
     14 #define eps  1e-6
     15 #define inf 10001000
     16 
     17 #define ll   __int64
     18 
     19 #define  read()  freopen("data.txt","r",stdin) ;
     20 #define inf  9999999
     21 using namespace std;
     22 
     23 const double pi  = acos(-1.0);
     24 const int maxn = 100010;
     25 #define N  30
     26 int n , m ;
     27 int dfn[maxn];// 记录 入栈的次序;
     28 int low[maxn];// 记录 最小的 可以到达 的次序
     29 int stack[maxn] ;//
     30 int  instack[maxn];//记录 是否在栈中
     31 int num ;//  入栈的次序
     32 int top;  // 栈顶
     33 int  bcnt ;  // 所点的 代表 序号
     34 int belong[maxn];//  记录每个节点所属 的 缩点号;
     35 vector<int>g[maxn] ;
     36 int ans[maxn] ;
     37 int in[maxn],out[maxn] ;
     38 int f[maxn],father[maxn] ;
     39 int cut ;
     40 int find(int x)
     41 {
     42     if(f[x]!=x) f[x] = find(f[x]) ;
     43     return f[x] ;
     44 }
     45 int link(int i,int  j)// 判断是否在同一个 缩点 里面
     46 {
     47     int a = find(i) ;
     48     int b = find(j) ;
     49     if(a!=b)
     50     {
     51         f[a] = b;
     52         return 1 ;
     53     }
     54 
     55     return 0 ;
     56 }
     57 void tarjan(int a,int pre)
     58 {
     59     int j ,i, k;
     60     dfn[a] = low[a]= ++num ;
     61 
     62     stack[++top] = a;
     63     instack[a] = 1 ;
     64     for(i = 0 ; i < g[a].size();i++)
     65     {
     66         int k = g[a][i] ;
     67         if(!dfn[k])
     68         {
     69             tarjan(k,a) ;
     70 
     71             father[k] = a ;
     72 
     73             if(low[a] > low[k]) low[a] = low[k] ;
     74 
     75             if(low[k] > dfn[a])cut ++ ;
     76             else
     77               link(a,k) ; // 将 不是 割边上的点 缩成一个点 ;
     78 
     79         }
     80         else
     81         {
     82             if(k != pre &&instack[k] && dfn[k] < low[a]) low[a] = dfn[k] ;//  这里不能为 父节点
     83         }
     84 
     85     }
     86 
     87 
     88 
     89 }
     90 
     91 void init()
     92 {
     93 
     94     CL(instack,0);
     95     CL(belong,0) ;
     96     CL(dfn,0) ;
     97     CL(low,0) ;
     98     CL(father,0) ;
     99     num = bcnt = top  = 0 ;
    100 
    101     for(int i = 0 ;i <=n;i++)f[i] = i ;
    102 
    103 
    104 
    105 }
    106 
    107 void  lca(int u,int v)// 最近公共祖先 模版
    108 {
    109     while(u!=v)
    110     {
    111 
    112         while(dfn[u] > dfn[v] && u!=v)
    113         {
    114             if(link(u,father[u])) cut--;
    115             else  u = father[u] ;
    116         }
    117         while(dfn[v] > dfn[u]&& u!=v)
    118         {
    119             if(link(v,father[v])) cut-- ;
    120             else v = father[v] ;
    121 
    122         }
    123 
    124     }
    125 }
    126 int  main()
    127 {
    128     int i ,a,b,t,j,mi,mx;
    129     int cas = 0 ;
    130     //read() ;
    131 
    132     while(scanf("%d%d",&n,&m)!=EOF)
    133     {
    134         if(n == 0&& m == 0break ;
    135 
    136         init() ;
    137 
    138         for(i = 0;i <= n;i++) g[i].clear() ;
    139 
    140         for(i =0  ; i < m;i++)
    141         {
    142             scanf("%d%d",&a,&b);
    143             g[a].push_back(b);
    144             g[b].push_back(a) ;
    145         }
    146         cut = 0 ;
    147         tarjan(1,-1) ;
    148         scanf("%d",&t);
    149 
    150         printf("Case %d:\n",++cas) ;
    151         while(t--)
    152         {
    153             scanf("%d%d",&a,&b);
    154             lca(a,b) ;
    155 
    156             printf("%d\n",cut) ;
    157         }
    158         printf("\n") ;
    159 
    160     }
    161 
    162 }
  • 相关阅读:
    最大子数组问题
    剑指offer python版 树的子结构
    剑指offer python版 重建二叉树
    剑指offer python版 字符串变成整数
    剑指offer python版 构建乘积数组
    剑指offer python版 不用加减乘除做加法
    剑指offer python版 求1+2+…+n
    剑指offer python版 股票最大收益
    剑指offer python版 圆圈中最后剩下的数字
    剑指offer python版 扑克牌的顺子
  • 原文地址:https://www.cnblogs.com/acSzz/p/2729660.html
Copyright © 2020-2023  润新知