• poj 3694 Network 【Tarjan】+【LCA】


    <题目链接>

    题目大意:

    给一个无向图,该图只有一个连通分量。然后查询q次,q < 1000, 求每次查询就增加一条边,求剩余桥的个数。

    解题分析:

    普通的做法就是在每加一条边后,都找一次桥,但是这样肯定超时。

    第一种做法是:缩点,因为如果一条边不是桥那么无论怎么加边他肯定都不会变成桥,这样把连通分量缩成一个点。这样全图所有的边就都是桥,这样的话,我们就在加的边里面去找如果加的边是同一个点,那么,肯定不会减少桥,但是如果不是同一个,那么桥肯定减少。

    还有一种做法:因为需要u、v之间直接连一条边,所以u->v的原始路径与新连的这条边构成一个环,所以u->v原始路径上的所有桥将不复存在。我们可以先利用Tarjan处理出原图中所有的桥,然后再利用LCA将u->v原始路径的每一条边都求出来(求出u到LCA的所有边和v到LCA的所有边),然后判断该边是否是桥即可,如果是桥,则删除该边的桥标记即可。

    下面介绍第二种做法:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 #define clr(a,b) memset(a,b,sizeof(a))
     7 const int N = 1e5+10;
     8 const int M = 4e5+10;
     9 int n,m,q,tot,index,bridge;
    10 int dfn[N],low[N],fa[N],dep[N],head[N];
    11 bool cut[N];
    12 struct Edge{
    13     int to,next;
    14 }edge[M];
    15 void init(){
    16     tot=bridge=index=0;
    17     clr(head,-1);clr(dfn,0);clr(dep,0);clr(cut,false);
    18 }
    19 void addedge(int u,int v){
    20     edge[tot].to=v,edge[tot].next=head[u];
    21     head[u]=tot++;
    22 }
    23 void tarjan(int u,int pre){
    24     dfn[u]=low[u]=++index;
    25     dep[u]=dep[pre]+1;       //dep代表该点深度
    26     for(int i=head[u]; i!=-1; i=edge[i].next){
    27         int v=edge[i].to;
    28         if(v==pre) continue;
    29         if(!dfn[v]){
    30             fa[v]=u;
    31             tarjan(v,u);
    32             low[u]=min(low[u],low[v]);
    33             if(low[v]>dfn[u]){     //桥的判定定理            
    34                 cut[v]=1;   //标记v所在边为桥
    35                 bridge++;
    36             }
    37         }
    38         else
    39             low[u]=min(low[u],dfn[v]);
    40     }
    41 }
    42 void LCA(int u,int v){    //利用LCA将u->v原始路径上的所有桥全部删除
    43     if(dep[u]<dep[v]) swap(u,v);
    44     while(dep[u]>dep[v]){     //将u跳到与v深度相同,将路径上碰到的桥全部删除   
    45         if(cut[u]){        
    46             bridge--;
    47             cut[u]=false;
    48         }
    49         u=fa[u];
    50     }
    51     while(u!=v){        //将u和v同时跳到他们的LCA,在路径中,凡是碰到桥,将该桥删除
    52         if(cut[u]){
    53             bridge--;
    54             cut[u]=false;
    55         }
    56         if(cut[v]){
    57             bridge--;
    58             cut[v]=false;
    59         }
    60         u=fa[u],v=fa[v];
    61     }
    62 }
    63 int main(){
    64     int ncase=0;
    65     while(~scanf("%d%d",&n,&m) && (n||m)){
    66         init();
    67         for(int i=1; i<=m; i++){        
    68             int u,v;scanf("%d%d",&u,&v);
    69             addedge(u,v);addedge(v,u);
    70         }
    71         tarjan(1,0);    //预处理出原图中所有的桥
    72         scanf("%d",&q);
    73         printf("Case %d:
    ",++ncase);
    74         while(q--){           
    75             int u,v;scanf("%d%d",&u,&v);
    76             LCA(u,v);    //u,v之间连一条边,则改变与u->v的原始路径构成环,所以u->v原始路径上的所有桥将不复存在
    77             printf("%d
    ",bridge);
    78         }puts("");
    79     }
    80     return 0;
    81 }

    2018-11-06

  • 相关阅读:
    Java——通过Java代码启动批处理文件
    成功解决错误1130 Host xxx is not allowed to connect to this MySQL server
    SQL全文索引的作用(转)
    查找不重复记录
    全文索引原理和一个完整的SQL SERVER数据库全文索引的示例(转)
    C# 参考:令人惊喜的泛型委托 Predicate/Func/Action
    moss 外网访问设置
    SQL2000和SQL2005的行转列处理方法
    海量数据库查询
    MSSQL 查询优化二(转)
  • 原文地址:https://www.cnblogs.com/00isok/p/9912428.html
Copyright © 2020-2023  润新知