zoukankan      html  css  js  c++  java
  • 无向图是否是无环连通图的判别

    这是2020的最后一篇博客,对今天数据结构小测的一道题总结一下。

    题目:给定顶点个数n和无向图的邻接矩阵bool m[graph_size][graph_size],写出判断是否为无环连通图的函数bool Isconnectedacyclic()。

    上午写的时候只想到深搜/广搜,下午听老师讲了一下,想到了其他方法,这里总结三种,如有错误请指正。

    1.深搜/广搜

    本来我是打算写深搜的,但由于给定的函数没有参数,懒得再写一个函数了。深搜应该是比较直接的方法,这里不多赘述

    而广搜比深搜麻烦的一点是新加入的点要考虑父节点,从而避免重复访问。这里有两种方法:一是对新加入的点记录父节点,在对边遍历时遇到父节点则跳过;二是利用邻接矩阵对边访问的特性,直接删掉用过的边和对称的边。下面给出第二种的代码:

     1 bool Isconnectedacyclic()
     2 {
     3     vector<bool>vit(n,false);
     4     queue<int>que;
     5     bool flag=false;
     6     que.push(0);
     7     vit[0]=true;
     8     while(!que.empty())
     9     {
    10         int p=que.front();
    11         que.pop();
    12         for(int i=0;i<graph_size;++i)
    13         {
    14             if(m[p][i])
    15             {
    16                 if(vit[i])flag=true;
    17                 else
    18                 {
    19                     vit[i]=true;
    20                     que.push(i);
    21                 }
    22                 m[p][i]=m[i][p]=false; //删边
    23             }
    24         }
    25     }
    26     if(flag)return false; //有回路
    27     for(int i=0;i<n;++i)
    28     {
    29         if(!vit[i])return false; //非联通图
    30     }
    31     return true;
    32 }

    2.并查集:

    其实跟kruskal算法基本一样,对所有的边遍历,如果两个顶点在同一集合说明有环,否则将他们合并。如果有两个以上连通分支说明非连通图。

    下面是代码:

     

     1  int f[n];
    2
    int find(int k) 3 { 4 if(f[k]==k)return k; 5 return f[k]=find(f[k]); 6 } 7 bool Isconnectedacyclic() 8 { 9 for(int i=0;i<n;++i)f[i]=i; 10 for(int i=0;i<graph_size;++i) 11 { 12 for(int j=i+1;j<graph_size;++j) 13 { 14 if(m[i][j]) 15 { 16 int fi=find(i),fj=find(j); 17 if(fi==fj)return false; 18 f[fi]=fj; 19 } 20 } 21 } 22 int cnt=0; 23 for(int i=0;i<n;++i) 24 { 25 if(f[i]==i)cnt++; 26 } 27 return cnt==1;
    28 }

    3.树的性质:

    写的时候没有想起(好不应该),一个无环连通图正是一棵树。根据树的性质,边数m=顶点数n -1,我们统计总共有多少条边,如果m<n-1说明非连通;如果m>n-1说明必定有环;如果m==n-1,还要对图进行一次遍历,判断是否为连通图。

    以下是代码:

     1 bool Isconnectedacyclic()
     2 {
     3     int cnt=0;
     4     for(int i=0;i<graph_size;++i)
     5     {
     6         for(int j=i+1;j<graph_size;++j)
     7         {
     8             if(m[i][j])cnt++;
     9         }
    10     }
    11     if(cnt!=n-1)return false;
    12     vector<bool>vit(n,false);
    13     queue<int>que;
    14     que.push(0);
    15     vit[0]=true;
    16     while(!que.empty())
    17     {
    18         int p=que.front();
    19         que.pop();
    20         for(int i=0;i<graph_size;++i)
    21         {
    22             if(m[p][i]&&!vit[i])
    23             {
    24                 vit[i]=true;
    25                 que.push(i);
    26             }
    27         }
    28     }
    29     for(int i=0;i<n;++i)
    30     {
    31         if(!vit[i])return false;
    32     }
    33     return true;
    34 }
  • 相关阅读:
    为初次使用linux设置 root密码
    linux如何改为汉化环境
    Linux 标准目录结构
    常用linux terminal 命令
    jquery 获取及设置input各种类型的值
    使用$.getJSON实现跨域ajax请求
    react 异步取数据
    PHP 全局变量
    PHP保存本地日志文件
    全端开发——css(选择器)
  • 原文地址:https://www.cnblogs.com/yanying7/p/14218535.html
Copyright © 2011-2022 走看看