C++图论

图的相关概念

图论(Graph Theory)以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些实体之间的某种特定关系,用点代表实体,用连接两点的线表示两个实体间具有的某种关系。图可以表示为G=(V,E),其中V是顶点的有穷(非空)集合,E为边的集合。

图的分类

无向图:边集E(G)中为无向边。
有向图:边集E(G)中为有向边。
带权图 :边上带有权的图。也称为网。(有向带权图、无向带权图)
简单图 (simple graph):若一个图中没有自环和重边,它被称为简单图。具有至少两个顶点的简单无向图中一定存在度相同的结点。

顶点的度、入度、出度

顶点的度:与该顶点相关联的边的数目,有奇点、偶点之分。
对于有向图:有入度和出度之分
入度:该顶点的入边的数目。
出度:该顶点的出边的数目。

完全图、稠密图、稀疏图

完全图:若是无向图中,则每两个顶点之间都存在着一条边;若是有向图,则每两个顶点之间都存在着方向相反的两条边。n阶的完全有向图含有n*(n-1)条边,n阶完全无向图含有n*(n-1)/2条边
稀疏图 (sparse graph):若一张图的边数远小于其点数的平方,那么它是一张 稀疏图。
稠密图 (dense graph):若一张图的边数接近其点数的平方,那么它是一张稠密图。

路径

在图G=(V,E)中,若从顶点vi出发,沿一些边经过一些顶点vp1,vp2,…,vpm,到达顶点vj。则称顶点序列(vi vp1 vp2 … vpm vj)为从顶点vi到顶点vj的路径。它经过的边(vi,vp1)、(vp1,vp2)、…、(vpm,vj)应是属于E的边。非带权图的路径长度是指路径上边的条数。带权图的路径长度是指路径上各边的权之和。
若路径上除vi、vj外其余各顶点均不互相同,则称这样的路径为简单路径。起点和终点相同的简单路径称为简单回路或环。

连通和连通分量

连通:在一个图中,如果从顶点U到顶点V有路径,则称U和V是连通的;
连通图:如果一个无向图中,任意两个顶点之间都是连通的,则称该无向图为连通图。否则称为非连通图;左图为一个连通图。
连通分量:一个无向图的连通分支定义为该图的最大连通子图,左图的连通分量是它本身。

注意:任何连通图的连通分量只有一个,即本身,而非连通图有多个连通分量!!!!!

强连通图和强连通分量

强连通图:在一个有向图中,对于任意两个顶点U和V,都存在着一条从U到V的有向路径,同时也存在着一条从V到U的有向路径,则称该有向图为强连通图;右图不是一个强连通图。
强连通分量:一个有向图的强连通分量定义为该图的最大的强连通子图,右图含有两个强连通分量,一个是1和2构成的一个子图,一个是3独立构成的一个子图。

注意:强连通图只有一个强连通分量,即本身,非强连通图有多个强连通分量!!!!!

C++图论简介与实现

图论是计算机科学中一个重要的领域,用于研究图数据结构以及图算法。图由节点(顶点)和连接节点的边组成,可以用于表示各种关系和网络结构。在本篇博客中,我们将介绍C++中常用的图论算法,并给出相应的代码实现。

图的表示

图可以用多种方式进行表示,常见的有邻接矩阵和邻接链表。在C++中,我们可以使用二维数组或者容器来表示图。

邻接矩阵表示

邻接矩阵是一个二维数组,用于表示图中每个节点之间的连接关系。如果节点i和节点j之间有一条边,则邻接矩阵中的第i行第j列和第j行第i列的元素为1,否则为0。

const int MAX_NODES = 100;
int adjMatrix[MAX_NODES][MAX_NODES];

void addEdge(int u, int v) {
    adjMatrix[u][v] = adjMatrix[v][u] = 1;
}

邻接链表表示

邻接链表是一种更灵活的图表示方法,它使用一个数组或者容器来存储每个节点的邻居节点。在C++中,我们可以使用vector或者list来实现邻接链表。

const int MAX_NODES = 100;
vector<int> adjList[MAX_NODES];

void addEdge(int u, int v) {
    adjList[u].push_back(v);
    adjList[v].push_back(u);
}

图的遍历

图的遍历是指以某个节点为起点,依次访问图中的所有节点。常见的图遍历算法有深度优先搜索(DFS)和广度优先搜索(BFS)。

深度优先搜索

深度优先搜索是一种递归的图遍历算法,它从起点开始,依次访问起点的邻居节点,然后再访问邻居节点的邻居节点,直到遍历完所有的节点。

bool visited[MAX_NODES];

void dfs(int u) {
    visited[u] = true;
    cout << u << " ";

    for (int v : adjList[u]) {
        if (!visited[v]) {
            dfs(v);
        }
    }
}

广度优先搜索

广度优先搜索是一种非递归的图遍历算法,它从起点开始,依次访问起点的邻居节点,然后再访问邻居节点的邻居节点,直到遍历完所有的节点。广度优先搜索使用队列来保存待访问的节点。

bool visited[MAX_NODES];

void bfs(int u) {
    queue<int> q;
    visited[u] = true;
    q.push(u);

    while (!q.empty()) {
        int v = q.front();
        q.pop();
        cout << v << " ";

        for (int w : adjList[v]) {
            if (!visited[w]) {
                visited[w] = true;
                q.push(w);
            }
        }
    }
}

图的最短路径

最短路径是指在图中找到两个节点之间最短的路径。常见的最短路径算法有Dijkstra算法和Bellman-Ford算法。

Dijkstra算法

Dijkstra算法是一种贪心算法,用于求解带权图中的最短路径。它从起点开始,依次更新起点到其他节点的最短路径,并选择当前最短路径的节点作为下一个节点。

const int INF = INT_MAX;

void dijkstra(int start) {
    vector<int> dist(MAX_NODES, INF);
    dist[start] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({0, start});

    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();

        for (int v : adjList[u]) {
            int weight = 1; // 假设边的权重都为1
            if (dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
                pq.push({dist[v], v});
            }
        }
    }
}

Bellman-Ford算法

Bellman-Ford算法是一种动态规划算法,用于求解带权图中的最短路径。它从起点开始,依次更新起点到其他节点的最短路径,直到没有更新操作为止。

const int INF = INT_MAX;

void bellmanFord(int start) {
    vector<int> dist(MAX_NODES, INF);
    dist[start] = 0;

    for (int i = 0; i < MAX_NODES - 1; i++) {
        for (int u = 0; u < MAX_NODES; u++) {
            for (int v : adjList[u]) {
                int weight = 1; // 假设边的权重都为1
                if (dist[u] + weight < dist[v]) {
                    dist[v] = dist[u] + weight;
                }
            }
        }
    }
}

总结

图论在计算机科学中有着广泛的应用,涉及到图的表示、遍历和最短路径等问题。本篇博客介绍了C++中常用的图论算法,并给出了相应的代码实现。希望对读者能有所帮助。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值