洛谷题单指南-最短路-P6464 [传智杯 #2 决赛] 传送门

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

题意解读:将任意两点连一条权值为0的边,计算所有不同两点最短路之和的最小值。

解题思路:

1、朴素想法

枚举所有可能连0边的两点(O(n^2)),建立0边之后跑Floyd算法(O(n^3)),然后更新答案。

总体复杂度为O(n^5),需要进行优化。

2、优化方法

对于每一次两点建0边,都跑一遍完整的Floyd算法,是比较浪费的!

因为Floyd会更新所有两点之间的最短路,而两点建0边,只会影响经过这两点的所有路径的最短路。

所以跑Floyd时没有必要枚举所有的中间点,只需要固定建0边的2个点,更新经过这两个点的所有路径的最短路即可!

这样复杂度可以优化到O(n^4)。

100分代码:

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

const int N = 205;
int d[N][N], b[N][N];
int n, m;

int main()
{
    memset(d, 0x3f, sizeof(d));
    cin >> n >> m;
    while(m--)
    {
        int u, v, w;
        cin >> u >> v >> w;
        d[u][v] = d[v][u] = w;
    }
    for(int i = 1; i <= n; i++)
    {
        d[i][i] = 0;
    }
    
    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]);
    
    int ans = 2e9;

    //枚举所有可能的传送门
    for(int x = 1; x < n; x++)
    {
        for(int y = x; y <= n; y++)
        {
            memcpy(b, d, sizeof(d)); //把d复制一份到b
            b[x][y] = b[y][x] = 0; //传送门对应的路径长度置为0

            //对于经过传送门中点x的最短路进行floyd操作
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                    b[i][j] = min(b[i][j], b[i][x] + b[x][j]);
            //对于经过传送门中点y的最短路进行floyd操作
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                    b[i][j] = min(b[i][j], b[i][y] + b[y][j]);
            
            //更新一次答案
            int res = 0;
            for(int i = 1; i < n; i++)
                for(int j = i + 1; j <= n; j++)
                    res += b[i][j];
            
            ans = min(ans, res);
        }
    }

    cout << ans;

    return 0;
}

 

posted @ 2025-04-12 18:04  hackerchef  阅读(36)  评论(0)    收藏  举报