• 关键城市--图的割点 《啊哈算法》代码详解


    #include<iostream>
    using namespace std;
    int n,m,e[9][9],root;
    int num[9],low[9],flag[9],index;
    
    void dfs(int cur,int father)
    {
        int child=0;
        index++;
        num[cur]=index;
        low[cur]=index;
        for(int i=1;i<=n;i++){
            if(e[cur][i]==1){//i是不通过父亲可以到达的节点
                if(num[i]==0){//如果是爸爸,就不会是0
                              //如果不是爸爸,就一定是自己祖先
                              //也就是说,你走了一个环
                              //因为这是深搜,当然这个祖先并不一定是最高层的那个,而是,总之要比爸爸先访问到
                    child++;
                    dfs(i,cur);//通过自己的儿子开始找祖先了
                    low[cur]=min(low[cur],low[i]);//既然cur可以不通过爸爸到达i,那么,i可以不通过自己爸爸到达的节点,cur一样可以到
                                                  //这样的话,虽然cur比i先访问到,但是极有可能通过i找到已经访问过个点了。
                                                  //如果真能找到,cur就不是割点了。
                    if(cur!=root&&low[i]>=num[cur]){//这就是找不到了,因为low的初始值一定比num大,所以不通过爸爸找不到祖宗的话,
                                                    //low[i]的值是不会比num[cur]小的。
                        flag[cur]=1;
    
                    }
                    if(cur==root&&child==2){//child等于2的时候,说明根节点一定是割点
                                            //因为,只有当自己的儿子没有被访问过,才会是自己的亲儿子
                                            //简单来说,在程序开始,确定好了一个与之相邻的结点是儿子了之后,就会马上开始深搜
                                            //搜索之后,与之相邻的其他结点,如果被访问过了,则不会进入这个if,所以就不会有新的儿子
                                            //所以儿子数唯二,根节点一定是割点。
                                            //儿子数为三也是的,但是再成为三之前,已经在成为二的时候被确认过了,所以写等于2没有问题。
                        flag[cur]=1;
                    }
                }
                else if(i!=father){//绝不是爸爸,而是祖先
                    low[cur]=min(low[cur],num[i]);//这句话才是核心啊!!!
                }
            }
        }
        return;
    }
    
    
    
    int main()
    {
        int x,y;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                e[i][j]=0;
            }
        }
    
        for(int i=1;i<=m;i++){
            cin>>x>>y;
            e[x][y]=1;
            e[y][x]=1;
    
        }
    
        root=1;
        dfs(1,root);
    
        for(int i=1;i<n;i++){
            if(flag[i]==1){
                cout<<i<<" ";
            }
        }
    }
    

      让我们思考一下,这个程序用到了num与low数组,而我们也在Tarjan里面,同样用到了这两个数组,并且他们表达的含义相同,那么,我们就会自然地思考,这两个算法有何相似之处,以及有什么区别.

      首先,求割边的算法,并未试图将原有的图划分为几个部分,而是求可以将图划开的图的点。这体现在,在这个算法之类,更新low数组,没有经过父节点。

  • 相关阅读:
    每天学习算法二
    每天学习算法 一
    数据量基础
    SQL server数据库创建代码,filegroup文件组修改,
    SQL学习笔记之 数据库基础(一)
    Oracle的查询-条件表达式
    Oracle的查询-单行查询
    Oracle 的查询-scott用户介绍
    Oracle的基本操作-序列的使用
    Oracle的基本操作-修改表结构、数据的增删改查
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/9114416.html
Copyright © 2020-2023  润新知