C++图的算法应用

本文介绍了图论中的重要算法,包括Prim和Kruskal算法用于找到无向图的最小生成树,以及Dijkstra和Bellman-Ford算法解决单源最短路问题。同时,还提到了邻接矩阵和邻接表作为图的两种建模方式,以及Floyd算法用于求解所有顶点间的最短路径和传递闭包的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最小生成树

最小生成树 (Minimum Spanning Tree, MST) 是指在一个无向连通图中找到一个树,使得该树包含图中所有顶点,并且边的权值之和最小。常用的算法有Prim算法和Kruskal算法。

Prim算法

Prim算法是一种贪心算法,从一个顶点开始,每次选择与当前生成树相连的权值最小的边,直到生成树包含所有顶点为止。

以下是Prim算法的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1005;

int graph[MAXN][MAXN];
int dist[MAXN];
bool visited[MAXN];

int prim(int n) {
    int minCost = 0;

    memset(dist, INF, sizeof(dist));
    memset(visited, false, sizeof(visited));

    dist[1] = 0;

    for (int i = 1; i <= n; i++) {
        int u = -1;

        for (int j = 1; j <= n; j++) {
            if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
                u = j;
            }
        }

        visited[u] = true;
        minCost += dist[u];

        for (int v = 1; v <= n; v++) {
            if (!visited[v] && graph[u][v] < dist[v]) {
                dist[v] = graph[u][v];
            }
        }
    }

    return minCost;
}

Kruskal算法

Kruskal算法是一种基于并查集的贪心算法,它按照边的权值从小到大的顺序选择边,并且保证选中的边不会构成环。

以下是Kruskal算法的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;

struct Edge {
    int u, v, weight;
    bool operator<(const Edge& other) const {
        return weight < other.weight;
    }
};

int parent[MAXN];
vector<Edge> edges;

int findParent(int x) {
    if (parent[x] == x) {
        return x;
    }
    return parent[x] = findParent(parent[x]);
}

int kruskal(int n) {
    int minCost = 0;

    sort(edges.begin(), edges.end());

    for (int i = 1; i <= n; i++) {
        parent[i] = i;
    }

    for (int i = 0; i < edges.size(); i++) {
        int u = edges[i].u;
        int v = edges[i].v;
        int weight = edges[i].weight;

        int parentU = findParent(u);
        int parentV = findParent(v);

        if (parentU != parentV) {
            parent[parentU] = parentV;
            minCost += weight;
        }
    }

    return minCost;
}

单源最短路

单源最短路 (Single Source Shortest Path, SSSP) 是指在图中找到从一个源点到其它所有顶点的最短路径。常用的算法有Dijkstra算法和Bellman-Ford算法。

Dijkstra算法

Dijkstra算法是一种贪心算法,从源点开始,每次选择与当前顶点距离最短的顶点,并更新其它顶点的最短距离。

以下是Dijkstra算法的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1005;

int graph[MAXN][MAXN];
int dist[MAXN];
bool visited[MAXN];

void dijkstra(int n, int source) {
    memset(dist, INF, sizeof(dist));
    memset(visited, false, sizeof(visited));

    dist[source] = 0;

    for (int i = 1; i <= n; i++) {
        int u = -1;

        for (int j = 1; j <= n; j++) {
            if (!visited[j] && (u == -1 || dist[j] < dist[u])) {
                u = j;
            }
        }

        visited[u] = true;

        for (int v = 1; v <= n; v++) {
            if (!visited[v] && graph[u][v] != INF && dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
}

Bellman-Ford算法

Bellman-Ford算法是一种动态规划算法,通过对所有边进行n-1轮松弛操作,可以找到从源点到其它所有顶点的最短路径。

以下是Bellman-Ford算法的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1005;

struct Edge {
    int u, v, weight;
};

int dist[MAXN];
vector<Edge> edges;

void bellmanFord(int n, int source) {
    memset(dist, INF, sizeof(dist));

    dist[source] = 0;

    for (int i = 1; i <= n - 1; i++) {
        for (int j = 0; j < edges.size(); j++) {
            int u = edges[j].u;
            int v = edges[j].v;
            int weight = edges[j].weight;

            if (dist[u] != INF && dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
            }
        }
    }
}

建图方式

建图方式通常有两种:邻接矩阵和邻接表。

邻接矩阵

邻接矩阵是一个二维数组,其中的元素表示两个顶点之间的边的权值。

以下是使用邻接矩阵建图的C++代码示例:

const int MAXN = 1005;
const int INF = 0x3f3f3f3f;

int graph[MAXN][MAXN];

void addEdge(int u, int v, int weight) {
    graph[u][v] = weight;
    graph[v][u] = weight; // 如果是有向图,则不需要这一行
}

void initGraph(int n) {
    memset(graph, INF, sizeof(graph));
}

邻接表

邻接表是一种链表的形式,其中的每个节点表示一个顶点,每个节点的邻居节点表示与该顶点相连的边。

以下是使用邻接表建图的C++代码示例:

const int MAXN = 1005;
const int INF = 0x3f3f3f3f;

struct Node {
    int v, weight;
};

vector<Node> graph[MAXN];

void addEdge(int u, int v, int weight) {
    graph[u].push_back({v, weight});
    graph[v].push_back({u, weight}); // 如果是有向图,则不需要这一行
}

void initGraph(int n) {
    for (int i = 1; i <= n; i++) {
        graph[i].clear();
    }
}

Floyd算法

Floyd算法是一种动态规划算法,通过对所有顶点之间的路径进行松弛操作,可以找到所有顶点之间的最短路径。

以下是Floyd算法的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1005;

int dist[MAXN][MAXN];

void floyd(int n) {
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
}

传递闭包

传递闭包是指在一个有向图中,对于任意两个顶点u和v,如果存在一条从u到v的路径,则称u可以到达v。传递闭包可以用于判断两个顶点之间是否存在路径。

以下是传递闭包的C++代码:

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;

bool reach[MAXN][MAXN];

void transitiveClosure(int n) {
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
            }
        }
    }
}

希望以上内容能对你有所帮助!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值