C--路径问题

本文介绍了如何在C语言中使用动态规划解决有向无环图(DAG)上的最长路径问题,通过实例展示了如何构建邻接矩阵和使用动态规划数组dp来计算路径。同时,文章也提到了与之对比的最短路径问题及其经典算法,如Dijkstra算法。

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

最长路

在C语言中解决最长路问题通常涉及到图论中的算法,如Dijkstra算法、Bellman-Ford算法或Floyd-Warshall算法等。这些算法通常用于计算从一个顶点到其他所有顶点的最短路径,而不是最长路径。然而,对于某些特定类型的问题,如DAG(有向无环图)上的最长路径问题,我们可以使用动态规划或其他方法来求解。

下面是一个使用动态规划解决DAG上最长路问题的简单示例。假设我们有一个DAG,每个节点有一个权重,我们希望找到从起始节点到终止节点的最长路径。

#include <stdio.h>  
#include <stdlib.h>  
#include <limits.h> // 为了使用INT_MIN  
  
#define MAX_VERTICES 100  
  
int graph[MAX_VERTICES][MAX_VERTICES]; // 邻接矩阵表示图  
int dp[MAX_VERTICES]; // 动态规划数组  
int n; // 顶点的数量  
  
// 初始化图  
void initializeGraph() {  
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < n; j++) {  
            graph[i][j] = INT_MIN; // 初始化为最小整数值  
        }  
    }  
}  
  
// 添加边和权重到图中  
void addEdge(int u, int v, int weight) {  
    graph[u][v] = weight;  
}  
  
// 使用动态规划计算从起始节点到所有其他节点的最长路径  
void longestPath() {  
    // 初始化动态规划数组  
    for (int i = 0; i < n; i++) {  
        dp[i] = INT_MIN;  
    }  
  
    // 起始节点的最长路径是其自身的权重  
    dp[0] = graph[0][0];  
  
    // 遍历所有节点  
    for (int i = 0; i < n; i++) {  
        // 遍历从当前节点可达的所有节点  
        for (int j = 0; j < n; j++) {  
            if (graph[i][j] != INT_MIN) {  
                // 更新动态规划数组  
                if (dp[i] + graph[i][j] > dp[j]) {  
                    dp[j] = dp[i] + graph[i][j];  
                }  
            }  
        }  
    }  
  
    // 打印结果  
    printf("Longest path from start node:\n");  
    for (int i = 0; i < n; i++) {  
        if (dp[i] != INT_MIN) {  
            printf("Node %d: %d\n", i, dp[i]);  
        }  
    }  
}  
  
int main() {  
    n = 5; // 假设有5个节点  
    initializeGraph();  
  
    // 添加边和权重到图中  
    addEdge(0, 1, 3);  
    addEdge(0, 2, 2);  
    addEdge(1, 3, 1);  
    addEdge(2, 3, 4);  
    addEdge(3, 4, 5);  
  
    longestPath();  
  
    return 0;  
}

在这个示例中,我们使用一个邻接矩阵graph来表示DAG,并使用动态规划数组dp来计算从起始节点到所有其他节点的最长路径。longestPath函数执行动态规划计算,并打印结果。

请注意,这个示例仅适用于DAG上的最长路径问题。对于其他类型的问题,可能需要使用不同的算法或方法来解决。

最短路

在C语言中求解最短路径问题,通常会使用图论中的经典算法,如Dijkstra算法、Bellman-Ford算法或Floyd-Warshall算法。这些算法适用于求解带权重的图中从一个源点到其他所有点的最短路径问题。

下面是一个使用Dijkstra算法求解单源最短路径问题的C语言示例代码:

#include <stdio.h>  
#include <limits.h>  
  
#define INF INT_MAX  
#define V 9  // 假设图中有9个顶点  
  
int minDistance(int dist[], bool sptSet[]) {  
    int min = INF, min_index;  
  
    for (int v = 0; v < V; v++)  
        if (sptSet[v] == false && dist[v] <= min)  
            min = dist[v], min_index = v;  
  
    return min_index;  
}  
  
void printSolution(int dist[]) {  
    printf("Vertex   Distance from Source\n");  
    for (int i = 0; i < V; i++)  
        printf("%d \t\t %d\n", i, dist[i]);  
}  
  
void dijkstra(int graph[V][V], int src) {  
    int dist[V];  
    bool sptSet[V];  
    for (int i = 0; i < V; i++)  
        dist[i] = INF, sptSet[i] = false;  
  
    dist[src] = 0;  
  
    for (int count = 0; count < V - 1; count++) {  
        int u = minDistance(dist, sptSet);  
  
        sptSet[u] = true;  
  
        for (int v = 0; v < V; v++)  
            if (!sptSet[v] && graph[u][v] && dist[u] != INF && dist[u] + graph[u][v] < dist[v])  
                dist[v] = dist[u] + graph[u][v];  
    }  
  
    printSolution(dist);  
}  
  
int main() {  
    int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},  
                      {4, 0, 8, 0, 0, 0, 0, 11, 0},  
                      {0, 8, 0, 7, 0, 4, 0, 0, 2},  
                      {0, 0, 7, 0, 9, 14, 0, 0, 0},  
                      {0, 0, 0, 9, 0, 10, 0, 0, 0},  
                      {0, 0, 4, 14, 10, 0, 2, 0, 0},  
                      {0, 0, 0, 0, 0, 2, 0, 1, 6},  
                      {8, 11, 0, 0, 0, 0, 1, 0, 7},  
                      {0, 0, 2, 0, 0, 0, 6, 7, 0}  
                     };  
  
    dijkstra(graph, 0);  
  
    return 0;  
}

单源路径

要找到从单个源点到其他所有顶点的最短路径,我们可以使用Dijkstra算法。Dijkstra算法是一种贪心算法,它逐步找到从源点到所有其他顶点的最短路径。

下面是一个使用Dijkstra算法求解单源最短路径问题的C语言示例代码

#include <stdio.h>  
#include <limits.h>  
  
#define V 9  // 假设图中有9个顶点  
  
// 函数声明  
int minDistance(int dist[], bool sptSet[]);  
void printSolution(int dist[]);  
  
// 使用Dijkstra算法找到从源点src到所有其他顶点的最短路径  
void dijkstra(int graph[V][V], int src) {  
    int dist[V];  // 存储从源点到所有其他顶点的最短距离  
    bool sptSet[V]; // sptSet[i]将为true,如果顶点i已经包含在最短路径树中,或者距离已知  
  
    // 初始化所有距离为无穷大,并将源点距离设置为0  
    for (int i = 0; i < V; i++)  
        dist[i] = INT_MAX, sptSet[i] = false;  
    dist[src] = 0;  
  
    // 找到最短路径的顶点  
    for (int count = 0; count < V - 1; count++) {  
        int u = minDistance(dist, sptSet);  
  
        // 将找到的顶点添加到最短路径树中  
        sptSet[u] = true;  
  
        // 更新相邻顶点的距离  
        for (int v = 0; v < V; v++)  
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v])  
                dist[v] = dist[u] + graph[u][v];  
    }  
  
    // 打印最短路径  
    printSolution(dist);  
}  
  
// 返回距离最小的顶点,该顶点尚未包含在sptSet中  
int minDistance(int dist[], bool sptSet[]) {  
    int min = INT_MAX, min_index;  
  
    for (int v = 0; v < V; v++)  
        if (sptSet[v] == false && dist[v] <= min)  
            min = dist[v], min_index = v;  
  
    return min_index;  
}  
  
// 打印最短路径  
void printSolution(int dist[]) {  
    printf("Vertex   Distance from Source\n");  
    for (int i = 0; i < V; i++)  
        printf("%d \t\t %d\n", i, dist[i]);  
}  
  
int main() {  
    int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},  
                       {4, 0, 8, 0, 0, 0, 0, 11, 0},  
                       {0, 8, 0, 7, 0, 4, 0, 0, 2},  
                       {0, 0, 7, 0, 9, 14, 0, 0, 0},  
                       {0, 0, 0, 9, 0, 10, 0, 0, 0},  
                       {0, 0, 4, 14, 10, 0, 2, 0, 0},  
                       {0, 0, 0, 0, 0, 2, 0, 1, 6},  
                       {8, 11, 0, 0, 0, 0, 1, 0, 7},  
                       {0, 0, 2, 0, 0, 0, 6, 7, 0}  
                      };  
  
    dijkstra(graph, 0); // 从顶点0开始寻找最短路径  
  
    return 0;  
}

在这个示例中,dijkstra函数实现了Dijkstra算法。它接受一个邻接矩阵graph和一个源点src作为输入,并输出从源点到所有其他顶点的最短距离。minDistance函数用于找到尚未包含在最短路径树中且距离最小的顶点。printSolution函数则负责打印最短路径的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值