最短路径(案例+完整步骤说明+详细注释)

最短路径(案例+完整步骤说明+详细注释)

最短路径(案例+完整步骤说明+详细注释)_第1张图片
步骤:

这道题最应该注意的地方就是路径不是互通的,只能单方向行驶,这就需要多一道步骤:把原地图反过来,即map[i][j]与map[j][i]交换一下,再求i~1的距离的时候,就回到了1到i距离的问题

1~i的最短路径应该怎么求得?
最短路径(案例+完整步骤说明+详细注释)_第2张图片

首先以1为头结点:
1->2:8
1->3:8
1->4:999999(不可直达)
1->5:5

现在得到距离1 节点最近的是节点5,再把节点5作为中间点,看看能不能更新一下1到别的节点的距离:
5->3:6
5->4:2(999999>5+2,所以更新1->4:7)

此时距离1最近的点还是5,但是由于5已经被探索过了,所以现在没被探索的所有点里,距离1最近的是4,故使用4作为中间点,道理同上:
4->1:8
4->5:3
这里都比原来的1->1和1->5大,所以不更新距离

此时4也被探索过了,所以现在距离1最近的点为:2或3。
先看2为中间点:
2->3:5,这里肯定也是不更新了,因为1->3小于1->2->3

再以3为中间点:
3->5:6,不更新1->5

经过上面的步骤,现在已经得到1到各个点的最短距离了,然后翻转一下地图,即可求得各个点到1的最短距离了。
此处不做赘述,请自行理解,然后这里给出代码,里边有详细注释

#include 
using namespace std;
#define INF 100
int main(){
    int map[INF][INF], rMap[INF][INF],    ///地图和反向地图
    dis[INF],disR[INF],                   ///1~i的距离,以及反向后的1~i的距离
    book[INF],bookR[INF],                 ///记录被探索过的节点,0为未探索,1为探索过的
    n, m,                                 ///n个城市,m条单向路
    t1, t2, t3,                           ///t1~t2距离为t3
    u,uR,                                 ///用来保存最近的节点,作为下一个节点
    min,minR;                             ///用来保存距离最近节点的长度
    cin >> n >> m;
    for (int i = 1; i <= n; i++){         ///初始化地图、反向地图
        for (int j = 1; j <= n; j++) {
            map[i][j] = rMap[i][j] = ((i == j) ? 0 : INF*1000);
        }
    }
    for (int i = 1; i <= m; i++){         ///输入地图,并保存到map和rMap
        cin >> t1 >> t2 >> t3;
        map[t1][t2] = rMap[t2][t1] = t3;
    }
    for (int i = 1; i <= n; ++i) {         ///初始化各点与1节点的可达距离
        dis[i] = map[1][i];
        disR[i] = rMap[1][i];
        book[i] = bookR[i] = 0;           ///初始为未探索
    }book[1] = bookR[1] = 1;              ///从节点1开始
    for (int i = 1; i <= n - 1; i++){     ///开始探索路径,最多探索到n-1个节点
        min = minR = INF;                 ///
        for (int j = 1; j <= n; j++){     ///探索距离节点1的挨着的最短节点,并暂时保存到u,长度保存到min;反向同理
            if (book[j] == 0 && dis[j]<min){
                min = dis[j];
                u = j;
            }
            if (bookR[j] == 0 && disR[j]<minR){
                minR = disR[j];
                uR = j;
            }
        }
        book[u] = bookR[uR] = 1;          ///此时以u为节点,进行探索
        for (int k = 1; k <= n; k++)      ///找到被u箭头指向的结点,并更新u之后的1到k节点的距离:1~u + u~k = 1~k ;反向同理
        {
            if (map[u][k] < INF)
            {
                if (dis[k]> dis[u] + map[u][k])
                    dis[k] = dis[u] + map[u][k];
            }
            if (rMap[uR][k] < INF)
            {
                if (disR[k]> disR[uR] + rMap[uR][k])
                    disR[k] = disR[uR] + rMap[uR][k];
            }
        }
    }
    int sum=0;                            ///最后计算出和,输出
    for (int i = 1; i <= n; i++)
        sum+=disR[i]+dis[i];
    cout << sum << endl;
    return 0;
}

附加补充一下,要是双向通路的话,利用此法也可解决,只要更改一下地图就行了,把地图关于正对角线做一下对比,取其小再赋给双方,即min(a(i, j), a(j, i)) 再分别赋值给他们俩,然后步骤一样也可以解决。

你可能感兴趣的:(笔记,算法)