无向图的连通,有向图的强连通,环

判断无向图是否连通

  1. DFS,BFS遍历图,是否所有顶点都能访问到。
  2. 并查集。

判断图中是否有环

有向图:有向图中的环特指同向的环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hsVSlpDr-1584972787667)(http://note.youdao.com/noteshare?id=d98bba32026574ec204adac734ccdaf7&sub=4699EAF86DEF463A8BE50FC418E4108A)]
1、拓扑排序

//邻接表版
class Solution{
    
    
public:
    bool topologicalSort(vector<vector<int> >& graph){
    
    
        int V = graph.size();
        int in_degree[V] = {
    
    };
        for(vector<int> v:graph){
    
    
            for(int x:v) in_degree[x]++;
        }
        //topo
        int num = 0; //拓扑排序成功的顶点个数
        queue<int> q;
        for(int i=0; i<V; i++){
    
    
            if(in_degree[i]==0) q.push(i);
        }
        while(!q.empty()){
    
    
            int v = q.front();
            q.pop();
            cout<<v<<' ';
            num++;
            for(int u:graph[v]){
    
    
                in_degree[u]--;
                if(in_degree[u]==0) q.push(u);
            }
        }
        if(num==V) return true;
        else return false;
    }
};

2、tarjan算法(本质上是DFS)
有向图中的强连通分量要么是一个环,要么是一个点。tarjan

//邻接矩阵版
class Solution{
    
    
public:
    int V, time; //顶点个数,时间戳
    vector<int> dfn, low;
    vector<bool> in_stack; //记录顶点是否在栈内
    stack<int> s;

    vector<vector<int> > tarjan(vector<vector<int> >& graph){
    
    
        //init
        V = graph.size();
        dfn.resize(V, 0); //dfn[i]=0还可表示i还未访问到
        low.resize(V, 0);
        in_stack.resize(V, false);
        time = 1;
        vector<vector<int> > ans;
        //tarjan
        for(int i=0; i<V; i++){
    
    
            if(dfn[i]==0) DFS(i, graph, ans);
        }
        return ans;
    }

    void DFS(int i, vector<vector<int> >& graph, vector<vector<int> >& ans){
    
    
        s.push(i);
        in_stack[i] = true;
        dfn[i] = low[i] = time++;
        for(int j; j<V; j++){
    
    
            if(graph[i][j]){
    
    
                if(dfn[j]==0){
    
    
                    DFS(j, graph, ans);
                    low[i] = min(low[i], low[j]);
                }
                else if(in_stack[j]) low[i] = min(low[i], dfn[j]);
            }
        }
        if(dfn[i]==low[i]){
    
    
            vector<int> temp;
            int x;
            do{
    
    
                x = s.top();
                s.pop();
                temp.emplace_back(x);
            }while(x!=i);
            ans.emplace_back(temp);
        }
        return;
    }
};

无向图

1、n算法

//邻接矩阵版
class Solution{
    
    
public:
    bool nAlgorithm(vector<vector<int> >& graph){
    
    
        int V = graph.size();
        int degree[V] = {
    
    };
        for(int i=0; i<V; i++){
    
    
            for(int j=0; j<V; j++){
    
    
                if(graph[i][j]!=0){
    
    
                    degree[i]++;
                    degree[j]++;
                }
            }
        }
        //把所有度<=1的顶点入队,只要入过队,就一定不在环里
        queue<int> q;
        int num = 0; //入过队的顶点数
        for(int i=0; i<V; i++){
    
    
            if(degree[i]<=1) q.push(i);
        }
        while(!q.empty()){
    
    
            int v = q.front();
            q.pop();
            num++;
            for(int j=0; j<V; j++){
    
    
                if(graph[v][j]!=0){
    
    
                    degree[v]--;
                    degree[j]--;
                    if(degree[j]==1) q.push(j);
                }
            }
        }
        if(num<V) return true; //有环
        else return false;
    }
};

2、并查集
并查集一般用于处理树结构,树的边可视为有向边。
处理图时只能压缩路径,原始路径就丢失了,因此只能判断环的存在,不能输出环。
每遇到一条边,就union一次。如果存在环,那么处理到环封口的边上时,两个顶点的father相同。

//邻接矩阵版
class Solution{
    
    
public:
    vector<int> father; //father存原始路径

    bool cyclic(vector<vector<int> >& graph){
    
    
        int V = graph.size();
        father.resize(V);
        for(int i=0; i<V; i++) father[i] = i;
        for(int i=0; i<V; i++){
    
    
            for(int j=0; j<V; j++){
    
    
                if(graph[i][j]!=0){
    
    
                    if(!union_set(i, j)) return true; //有环
                }
            }
        }
        return false;
    }

    int findFather(int a){
    
    
        int t = a;
        while(a!=father[a]) a = father[a];
        while(t!=father[t]){
    
    
            int u = father[t];
            father[t] = a;
            t = u;
        }
        return a;
    }

    bool union_set(int a, int b){
    
    
        int fa=findFather(a), fb=findFather(b);
        if(fa!=fb){
    
    
            father[fa] = fb;
            return true;
        }
        else return false; //出现环
    }
};

3、DFS

猜你喜欢

转载自blog.csdn.net/sinat_37517996/article/details/105059459