zoukankan      html  css  js  c++  java
  • POJ1144 tarjan+网络中割点与割边的数量

    题目链接:http://poj.org/problem?id=1144

    割点与割边的数量我们可以通过tarjan的思想从一个点开始对其余点进行访问。访问的顺序构成一棵dfs树,其中根节点到任何一个结点都只有唯一的一条路径。算法基于以下两个定理:

    定理一

    dfs树的根结点T是割点当且仅当他有两个或者更多的子节点。因为dfs树上任何点的子树都是不连通的,否则就会构成环,与dfs树的定义矛盾。故定理得证。

    定理二

    dfs树上的非根结点是割点当且仅当u至少存在一个子节点v,v的所有后代都没有回退边连回u的祖先,也就是从v出发能够访问到的最浅的结点比u的深度大。因为此时把u割去之后一定会使得v为根的分支被割离。

    根据以上定理,我们只要记录dfs的顺序,每个点的开始访问的最浅dfs深度并进行比较,即low[v]>=low[u]就可以得到割点的数量。对于割边,我们只要u的子结点v有low[v]>num[u]就说明(u,v)是割边。

    代码如下:

     1 #include<cstdio>
     2 #include<vector>
     3 #include<string.h>
     4 using namespace std;
     5 const int maxn=109;
     6 int low[maxn],num[maxn];//分别保存dfs树上结点能到达的最浅深度和dfs的访问顺序
     7 bool iscut[maxn];//记录是否是割点
     8 vector<int>G[maxn];//存边
     9 int dfn;//记录递归的顺序,用于给num赋值 
    10 int ans=0;//ans记录割点的数量 
    11 int n;
    12 void tarjan(int u,int fa)//参数分别是当前搜索的结点以及其父结点 
    13 {
    14     low[u]=num[u]=++dfn;//设置dfs的访问顺序,u是dfs访问的第一个点 
    15     int child=0;//u的子树的数量
    16     for(int i=0;i<G[u].size();i++)
    17     {
    18         int v=G[u][i];
    19         if(!num[v])//v点没有进入过dfs树,也就是没有访问过 
    20         {
    21             child++;
    22             tarjan(v,u);
    23             low[u]=min(low[u],low[v]);//low[i]的意义是点i所能到的dfs深度最浅的值,father结点由child结点来更新
    24             if(low[v]>=num[u]&&u!=1)//注意要判断u不是根节点,因为定理中是分为非根节点以及根节点进行讨论的,根节点根节点最后讨论 
    25             {
    26                 iscut[u]=1; 
    27              } 
    28         }
    29 //        else low[u]=min(low[u],num[v]);
    30         else if(num[v]<num[u]&&v!=fa)// fa也是u的邻居,在之前已经访问过;
    31         //处理回退边 ,u的子节点可以不通过u访问u以上的结点 
    32         {
    33             low[u]=min(low[u],num[v]); 
    34         }
    35      }
    36      if(u==1&&child>=2)
    37      {
    38          iscut[u]=1;//根结点有两个或以上的独立子树 
    39       } 
    40 }
    41 int main()
    42 {
    43     while(scanf("%d",&n)&&n)
    44     {
    45         int t,k;
    46         for(int i=1;i<=n;i++)G[i].clear();
    47         memset(iscut,0,sizeof(iscut));
    48         memset(low,0,sizeof(low));
    49         memset(num,0,sizeof(num));
    50         ans=0;
    51         dfn=0;
    52         while(scanf("%d",&t)==1&&t)
    53         {
    54             while(getchar()!='
    ')
    55             {
    56                 scanf("%d",&k);
    57                 G[t].push_back(k);
    58                 G[k].push_back(t);
    59             }
    60         }
    61         tarjan(1,-1);
    62         for(int i=1;i<=n;i++)ans+=iscut[i];//扫描割点的数量
    63         
    64         printf("%d
    ",ans); 
    65     }
    66  } 

     

  • 相关阅读:
    JAVA基础知识|HTTP协议-两个特性
    JAVA基础知识|TCP/IP协议
    Spring Cloud|高可用的Eureka集群服务
    Hadoop环境搭建|第四篇:hive环境搭建
    C#中Func与Action的理解
    C# lambda表达式
    WPF ControlTemplate
    sublime text3插件安装及使用
    Dev Express之ImageComboBoxEdit,RepositoryItemImageComboBox使用方式
    SQL查询结果增加序列号
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12580810.html
Copyright © 2011-2022 走看看