LeetCode

2018-05-07  本文已影响2人  徐凯_xp

图(Graph)是由顶点的有穷非空集合和 顶点之间边 的集合组成,通常表示为: (Graph)
G(V, E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。 图分无向图与有向图,根据图的边长,又分带权图与不带权图。


图的构造与表示:临接矩阵
#include<stdio.h>
int main(){
    const int MAX_N = 5;//一共5个顶点
    int Graph[MAX_N][MAX_N] = {0};//使用邻接矩阵表示
    Graph[0][2] = 1;
    Graph[0][4] = 1;
    Graph[1][0] = 1;
    Graph[1][2] = 1;
    Graph[2][3] = 1;
    Graph[3][4] = 1;
    Graph[4][3] = 1;
    printf("Graph:\n");
    for(int i =0;i < MAX_N; i++){
        for(int j = 0; j< MAX_N;j++){
            printf("%d",Graph[i][j]);
        }
        printf("\n");
    }  
    return 0;
}

图的构造与表示:临接表

#include<stdio.h>
#include<vector>
struct GraphNode{
    int label;
    std::vector<GraphNode *> neighbors;
    GraphNode(int x): label(x){};
};
int main(){
    const int MAX_N = 5;
    GraphNode *Graph[MAX_N];//5个顶点
    for(int i = 0; i < MAX_N; i++){
        Graph[i] = new GraphNode(i);
    }
    Graph[0]->neighbors.push_back(Graph[2]);
    Graph[0]->neighbors.push_back(Graph[4]);
    Graph[1]->neighbors.push_back(Graph[0]);
    Graph[1]->neighbors.push_back(Graph[2]);
    Graph[2]->neighbors.push_back(Graph[3]);
    Graph[3]->neighbors.push_back(Graph[4]);
    Graph[4]->neighbors.push_back(Graph[3]);
    printf("Graph:\n");
    for(int i = 0; i < MAX_N; i++){
        printf("label(%d)",i);
        for(int j = 0; j < Graph->neighbors.size();j++){
            printg("%d",Graph[i]->neighbors[j]->label);
        }
        printf("\n");
    }
    for(int i =0; i< MAX_N; i++){
        delete Graph[i];
    }
return 0 ;
}
图的深度优先遍历

从图中某个顶点v出发,首先访问该顶点,然后 依次从它的各个未被访问的 邻接点出发深度 优先搜索遍历图,直至图中所有和v有路径相通且未被访问的顶点都被访问到。 若此时尚有 其他顶点未被访问到,则另选一个未被访问的顶点作 起始点,重复上述过程,直至图中 所有 顶点都被访问到为止。


#include<stdio.h>
#include<vector>
struct GraphNode{
    int label;
    std::vector<GraphNode *> neighbors;
    GraphNode(int x) : label(x){};
};
void DFS_graph(GraphNode *node, int visit[ ]){
    visit[node->label] = 1;//标记已访问的顶点
    printf("%d",node->label);
//访问相邻的且没有被访问的顶点
    for(int i = 0; i < node->neighbors.size(); i++){
        if(visit[node->neighbors[i]->label] == 0){
            DFS_graph(node->neighbors[i],visit);
        }
    }
}
int main(){
    const int MAX_N = 5;
    GraphNode *Graph[MAX_N];//创建图的顶点
    for(int i = 0; i < MAX_N ; i++){
        Graph[i] = new GraphNode(i);
//添加图的边,注意添加边的顺序
    Graph[0]->neighbors.push_back(Graph[4]);
    Graph[0]->neighbors.push_back(Graph[2]);
    Graph[1]->neighbors.push_back(Graph[0]);
    Graph[1]->neighbors.push_back(Graph[2]);
    Graph[2]->neighbors.push_back(Graph[3]);
    Graph[3]->neighbors.push_back(Graph[4]);
    Graph[4]->neighbors.push_back(Graph[3]);
    int visit[MAX_N] = 0;//标记已访问的顶点
    for(int i = 0; i < MAX_N; i++){
        if(visit[i] == 0){//顶点没有被标记才会访问
            printf("From label[%d] :",Graphp[i]->label);
            DFS_graph(Graph[i],visit);
            printf("\n");
        }
    }
    for(int i = 0; i < MAX_N; i++){
        delete Graph[i]; 
    }
    return 0;
    }
}
图的宽度优先遍历

从图中某个顶点v出发,在访问了 v之后依次访问v的各个未曾访问过的 邻接点,然后 分别从这些邻接点出发 依次访问它们的邻接点,并使得 “先被访问的顶点的邻接点 先 于后被访问的顶点的邻接点被访问 ”,直至图中所有 已被访问的顶点的邻接点 都被访 问到。如果此时图中尚有顶点 未被访问,则需要另选一个未曾被访问过的顶点作为新 的起始点,重复上述过程,直至图中所有顶点都被访问到为止。


void BFS_graph(GraphNode * node, int visit[]){
    std::queue<GraphNode *>Q;
    Q.push(node);
    visit[node->label] = 1;
    while(!Q.empty()){
        GraphNode *node = Q.front();
        Q.pop();
        printf("%d",node->label);
        for(int i =0; i < node->neighbors.size(); i++){
            if(visit[node->neighbors[i]->label == 0]){
                Q.push(node->neighbors[i]);
                visit[node->neighbors[i]->label] = 1;
            }
        }
    }
}
课程安排

LeetCode 207. Course Schedule
已知有n个课程,标记从0至n-1,课程之间是有依赖关系的,例如希望完成A课程 ,可能需要先完成B课程。已知n个课程的依赖关系,求是否可以将n个课程全部 完成。

思考与分析

n个课程,它们之间有m个依赖关系,可以看成顶点个数为n,边个数为m的有向图。 图1:n = 3, m = [[0, 1], [0, 2], [1, 2]];可以完成。
图2:n = 3, m = [[0, 1], [1, 2], [2, 0]];不可以完成。 故,若有向图无环,则可以完成全部课程,否则不能。问题转换成,构建图,并判 断图是否有环。


方法一:深度优先搜索

在深度优先搜索时,如果正在搜索某一顶点(还未退出该顶点的递归深度搜索),又 回到了该顶点,即证明图有环。


算法设计(无环)



#include<vector>
struct GraphNode{
    int label;
    std::vector<GraphNode *> neighbors;
    GraphNode(int x): label(x){};
};
//节点访问状态,-1没有访问过,0代表正在访问,1代表访问结束
bool DFS_graph(GraphNode *node,std::vector<int> &visit){
    visit[node->label] = 0;
    for(int i = 0; i < node->neighbors.size();i++){
        if(visit[node->neighbors[i]->label ]== -1){
            if(DFS_graph(node->neighbors[i],visit) == 0){
                return false;
            }
        }
       else if(visit[node->neighbors[i]->label ]== 0){
            return false;
        }
    
    }
    visit[node->label] = 1;
    return true;
}
方法二:拓扑排序(宽度优先搜索)

在宽度优先搜索时,只将入度为0的点添加至队列。当完成一个顶点的搜索(从队 列取出),它指向的所有顶点入度都减1,若此时某顶点入度为0则添加至队列,若完 成宽度搜索后,所有的点入度都为0,则图无环,否则有环。
入度:有多少个顶点指向该节点
出度:该节点指向几个节点

class Solution{
public:
    bool canFinish(int numCourse, 
        std::vector<std::pair<int,int>>&prerequisites){
        std::vector<GraphNode *>graph;
        std::vector<int> degree;//入度数组
        for(int i = 0; i < numCourse; i++){
            degree.push_back(0);
            graph.push_back(new GraphNode(i));
        }
        for(int i = 0; i < prerequisites.size(); i++){
            GraphNode *begin = graph[prerequisites[i].second];
            GraphNode *end = graph[prerequisites[i].first];
            begin->neighbors.push_back(end);
            degree[prerequisites[i].first]++;//入度++,即pair<课程1,课程2>,课程1的入度++
        }
        std::queue<GraphNode *>Q;
        for(int i=0; i < numCourses;i++){
            if(degree[i] == 0){
                Q.push(graph[i]);
            }
        }
        while(!Q.empty()){
            GraphNode *node = Q.front();
            Q.pop();
            for(int i = 0; i < node->neighbors.size(); i++){
                degree[node->neighbors[i]->label]--;
                if(degree[node->neighbors[i]->label] ==0){
                    Q.push(node->neighbors[i]);
                }
            }
        }
        for(int i =0;i< graph.size();i++){
            delete graph[i];
        }
        for(int i = 0; i< degree.size();i++){
            if(degree[i]){
                return false;
            }
        }
}
};
上一篇下一篇

猜你喜欢

热点阅读