最短路径问题以及包含过路费的问题--动态规划式的解法

本文从动态规划的角度解析dijkstra算法,用于解决最短路径问题,并扩展到考虑过路费的二维动态规划问题。通过维护状态数组,初始状态设置,以及循环寻找最优子问题来更新路径和费用,最终找到满足预算的最短距离。
摘要由CSDN通过智能技术生成

求最短路径的dijkstra算法(详细算法原理自行百度,本文简单从动态规划角度思考),可以看成是一个动态规划的方法。
动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。
dijkstra虽然没有递推公式,但是满足将大问题分解成子问题,当前问题的解由上一次子问题的解推出。

算法的思想是
使用了三个一维数组,分别是visit[k],pre_node[k],short[k]来分别表示是否经过k点,k点的前驱节点,到达k点的最短距离
初始状态,是所有点出了起点都没经过,所有点的前驱节点都是起点,到达所有点的最短距离是起点直达的距离(没有路径距离就是极大值)。

接着开始循环求子问题。
子问题是先找出没有经过的并且到起点最短距离不是极大值的点i(第一次肯定是离起点最近的点)
如果找不到这个点,跳出循环(结束循环的唯一条件,这样可以避免非联通图出错)
然后分别找出点i的邻点j,判断通过i到j的距离是否小于目前j到起点的距离
如果是,那就更新short[j]和pre_node[k]
最后可以通过pre_node[]来遍历最短路径

int minlength(int (*edge)[7])
{
      int short_p[7];
      int pre_node[7];
      int visit[7];
      for (int i = 1; i < 7; i++){
            visit[i] = 0;
            pre_node[i] = 1;//起点是1,初始化都从1开始,直接从起点到各个点是老路
            short_p[i] = edge[1][i];
      }
      short_p[1] = 0;
      visit[1] = 1;
      //for (int v = 0; v < 7; v++){//无法避免不是联通图的情况
      while (1){
            int min = max_n;
            int k = -1;
            for (int i = 2; i < 7; i++){
  //先找出没进过的并且离起点最近的点
                  if (!visit[i] && short_p[i] < min){
                        min = short_p[i];
                        k = i;
                  }
            }
            if (k == -1)
                  break;//找不到就跳出去,因为可能图不连通
            else
                  visit[k] = 1;
            for (int ii = 2; ii < 7; ii++){
  //以上面找到的点为基准,找出相邻没过的点,检查过这个点到相邻点近还是老路近
                  if (!visit[ii] && edge[k][ii] + min < short_p[ii]){
                        short_p[ii] = edge[k][ii] + min;
                        pre_node[ii] = k;//更改前节点
                  }
            }
      }
      return 0;
}
int main()
{
      int edge[7][7] = { max_n };
      for (
好的,我可以为您提供一个基于Dijkstra算法的C语言程序来解决这个问题。 首先,我们需要定义一个图的结构体来存储城市间高速公路长度和过路费的信息: ```c #define MAX_CITY 100 typedef struct { int distance[MAX_CITY][MAX_CITY]; // 城市间距离 int cost[MAX_CITY][MAX_CITY]; // 城市间过路费 int num_city; // 城市数量 } Graph; ``` 接下来,我们需要实现Dijkstra算法来计算最短路径和最便宜路径。这里我们使用一个一维数组dist和一个一维数组cost来分别记录从出发点到每个城市的最短路径和最小花费: ```c #define INF 0x3f3f3f3f void dijkstra(Graph *graph, int start, int dist[], int cost[]) { int visited[MAX_CITY] = {0}; dist[start] = 0; cost[start] = 0; for (int i = 0; i < graph->num_city; i++) { int min_dist = INF; int min_city = -1; for (int j = 0; j < graph->num_city; j++) { if (!visited[j] && dist[j] < min_dist) { min_dist = dist[j]; min_city = j; } } if (min_city == -1) break; visited[min_city] = 1; for (int j = 0; j < graph->num_city; j++) { if (!visited[j] && graph->distance[min_city][j] != INF) { int new_dist = dist[min_city] + graph->distance[min_city][j]; int new_cost = cost[min_city] + graph->cost[min_city][j]; if (new_dist < dist[j] || (new_dist == dist[j] && new_cost < cost[j])) { dist[j] = new_dist; cost[j] = new_cost; } } } } } ``` 最后,我们可以利用上述代码来实现一个读入城市间高速公路长度和过路费的图,然后根据游客提供的出发地和目的地输出最短路径和最便宜路径: ```c #include <stdio.h> #include <string.h> int main() { Graph graph; memset(graph.distance, 0x3f, sizeof(graph.distance)); memset(graph.cost, 0x3f, sizeof(graph.cost)); graph.num_city = 0; int num_road; scanf("%d", &num_road); for (int i = 0; i < num_road; i++) { int city1, city2, distance, cost; scanf("%d %d %d %d", &city1, &city2, &distance, &cost); graph.distance[city1][city2] = graph.distance[city2][city1] = distance; graph.cost[city1][city2] = graph.cost[city2][city1] = cost; graph.num_city = (city1 > graph.num_city) ? city1 : graph.num_city; graph.num_city = (city2 > graph.num_city) ? city2 : graph.num_city; } int start, end; scanf("%d %d", &start, &end); int dist[MAX_CITY], cost[MAX_CITY]; memset(dist, 0x3f, sizeof(dist)); memset(cost, 0x3f, sizeof(cost)); dijkstra(&graph, start, dist, cost); printf("最短路径长度:%d,最小花费:%d\n", dist[end], cost[end]); return 0; } ``` 请注意,上述代码只是一个简单的示例程序,实际应用中还需要考虑更多的细节问题,例如输入的城市编号是否合法等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值