洛谷题单指南-最短路-P2910 [USACO08OPEN] Clear And Present Danger S

原题链接:https://www.luogu.com.cn/problem/P2910

题意解读:求图中经过m个点的的最短路之和。

解题思路:要计算经过m个点的最短路之和,就是要知道m个点中每一段a1~a2,a2~a3...am-1~am的最短路

而求多源最短路,必须想到Floyd算法!

Floyd算法的核心原理是动态规划!

1、状态表示

设d[i][j][k]表示从i经过1~k的点到j的最短距离

2、状态转移

考虑从i到j是否经过k点,有两种可能:

  • 经过k点,则有d[i][j][k] = d[i][k][k-1] + d[k][j][k-1]
  • 不经过k点,则有d[i][j][k] = d[i][j][k-1]

综合得到:d[i][j][k] = min(d[i][j][k-1], d[i][k][k-1] + d[k][j][k-1])

由于第三维只依赖上一层,可以滚动数组优化,进而可以直接省掉这一维

则有:d[i][j] = min(d[i][j], d[i][k] + d[k][j])

3、初始化

d[i][i] = 0,如果i-j没有边则d[i][j]=INF,否则d[i][j]=i到j的边长

4、答案

d[i][j]即表示i到j的距离

在跑玩一遍Floyd之后,枚举所有m个点,累加相邻节点的最短路,和即为答案。

100分代码:

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

const int N = 105, M = 10005;
int a[M];
int d[N][N];
int n, m, ans;

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i++) cin >> a[i];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            cin >> d[i][j];

    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    
    for(int i = 1; i < m; i++) ans += d[a[i]][a[i + 1]];
    cout << ans;

    return 0;
}

 

posted @ 2025-04-06 21:37  hackerchef  阅读(43)  评论(0)    收藏  举报