POJ1144 tarjan+网络中割点与割边的数量

时间:2020-03-27
本文章向大家介绍POJ1144 tarjan+网络中割点与割边的数量,主要包括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()!='\n')
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\n",ans); 
65     }
66  } 

 

原文地址:https://www.cnblogs.com/randy-lo/p/12580810.html