经过指定点的最短路径

题目描述:

给出一个有 n 个顶点的有向网,指定其中 k 个顶点( 不含顶点 1 和顶点 n ),求从顶点 1 到顶点 n 的,经过那 k 个顶点的最短路。

输入:

第一行是 顶点数 n 和 弧数目 e 。 1 ≤ n ≤ 40 ,1 ≤ e ≤ n × n
接下来是 e 行,每行三个整数 i , j , v ( 其中 0 < i, j ≤ n , 0 < v ≤ 100 ) ,表示从 顶点 i 到 顶点 j 的一条权值为 v 的弧。
接下来是一个正整数 k ( 1 ≤ k ≤ n - 2 ),接下来是 k 个正整数,表示必须经过的 k 个顶点。

输出:

如果不存在满足条件的路径,输出一行 "No solution";
否则,输出两行:
第 1 行,该最短路的长度;
第 2 行从顶点 1 到顶点 n 的最短路,顶点之间用一个空格分隔,要求按路径的顶点次序,前一个顶点必须有弧指向后一个顶点

注意!!! 需要注意题目是否允许最短路径中出现重复的点,若允许则可用本算法,若不允许,则可用dfs算法,文末有对dfs算法的分析

思路:暴力枚举,先用Floyd计算出各点之间的最短距离,然后将所有指定点进行全排列,计算每个排列的路径长度,并不断更新最短距离值。

算法实现:
1.跑一遍Floyd,求各顶点之间的最短路径距离,同时保存各点之间的最短路径
2.对所有指定点进行全排列,对每个排列计算:顶点1到排列首顶点的距离+排列中相邻两点之间的距离+序列末顶点到顶点n的距离,并不断更新得到最短路径
3.特判不存在满足路径的情况

代码如下:

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

#define INF 0x3f3f3f3f //设无穷大值

int n, m, k, idx;
int dist[45][45];   //存储各顶点间的最短路
int path[45][45];   //用于floyd存储路径
int must[40];       //存储指定点序列
char temp[45], anspath[45];

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

//获取点a到点b最短路的中间路径(路径中不含a,b)
void getpath(int a, int b) {
    if (path[a][b] == -1)
        return;
    else {
        int k = path[a][b];
        getpath(a, k);
        anspath[idx++] = k;
        getpath(k, b);
    }
}

//将“点1沿着当前must数组中指定点的顺序走到点n的路径”保存到anspath数组
void savpath() {
    anspath[idx++] = 1;
    getpath(1, must[0]);
    for (int i = 0; i < k - 1; i++) {
        anspath[idx++] = must[i];
        getpath(must[i], must[i + 1]);
    }
    anspath[idx++] = must[k - 1];
    getpath(must[k - 1], n);
    anspath[idx++] = n;
}     

//返回 点1沿着当前must数组中指定点的顺序走到点n 的路径长度
int getdis() {
    int distance = dist[1][must[0]];
    if (dist[1][must[0]] == INF)
        return INF + 1;
    for (int i = 0; i < k - 1; i++) {
        if (dist[must[i]][must[i + 1]] == INF)
            return INF + 1;
        distance += dist[must[i]][must[i + 1]];
    }
    if (dist[must[k - 1]][n] == INF)
        return INF + 1;
    distance += dist[must[k - 1]][n];
    return distance;
}

int main() {

    memset(dist, 0x3f, sizeof dist);
    memset(path, -1, sizeof path);
    scanf("%d%d", &n, &m);

    int a, b, w;
    while (m--) {
        scanf("%d%d%d", &a, &b, &w);
        dist[a][b] = min(dist[a][b], w);
    }
    floyd();

    scanf("%d", &k);
    for (int i = 0; i < k; i++)
        scanf("%d", &must[i]);
    
    //判断点1能否走到点n
    if (dist[1][n] == INF) {
        printf("No solution\n");
        return 0;
    }

    //使用next_permutation函数前先对数组进行排序
    sort(must, must + k);
    int mindis = INF;
    do {
        int d = getdis();
        if (mindis > d) {//如果存在更短的路径则更新答案,并把路径存到anspath[]
            mindis = d;
            idx = 0;
            savpath();
        }
    } while (next_permutation(must, must + k));

    printf("%d\n", mindis);
    for (int i = 0; i < idx; i++)
        printf("%d ", anspath[i]);

    return 0;
}

本题的一个坑:使用dfs算法无法通过。

如果通过使用dfs算法记录所有点1到达点n并且经过指定点的路径,在其中取最小值并不正确。因为dfs算法要求路径中的点最多只出现一次,但经过指定点的最短路的路径中可能存在同一个点出现多次的情况,而这种情况恰好被dfs排除,因此本题不用dfs。

例:在如下图中,求点1经过点2,点3到达点4的最短路径和长度

如果我们用dfs求解,得到的最短路径为:1->2->3->4,长度为420

而用暴力方法得到的最短路答案为:1->2->3->2->4,长度为40,其中点2在路径中出现过两次

显然,后者所求的最短路径正确

  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在Matlab中,有一个名为SHPATH的函数可以于计算避障最路径规划。该函数可以通过给定一个由0(代表开放空间)和1(代表障碍物)组成的"地形"矩阵,计算两个指定点之间的最路径,并自动避开障碍物。这个函数采用了两阶段解决方案。在第一阶段,算法通过搜索开放空间找到两个指定点之间的路径。在第二阶段,算法通过避开障碍物来优化第一阶段找到的路径,以确保生成的最路径是有效且可行的。 如果您想要获取完整的代码并直接运行,可以在网上搜索"海神之光 Matlab避障最路径规划",找到相应的下载链接。请注意,该代码适用于Matlab 2014a或2019b版本。如果在运行代码时遇到任何问题,您可以私信博主进行咨询。 总结来说,Matlab中的避障最路径规划可以通过SHPATH函数实现,并且可以通过海神之光提供的代码进行运行。该方法适用于多种领域,包括路径规划、优化求解、神经网络预测、图像处理和语音处理等。如果您对这方面的内容感兴趣,可以点击博主的主页,了解更多相关信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [避障最路径(版本 1.3):计算平面中两点之间的最路径,避开障碍物。-matlab开发](https://download.csdn.net/download/weixin_38691199/19308755)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【路径规划】基于matlab A_star算法机器人避障最路径规划【含Matlab源码 2522期】.zip](https://download.csdn.net/download/TIQCmatlab/87710424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [【路径规划】基于A_star算法机器人避障最路径规划附matlab代码.zip](https://download.csdn.net/download/qq_59747472/87673994)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值