【洛谷P6464】传送门

每天刷个一两题 比较值得写的会写在这里

P6464 [传智杯 #2 决赛] 传送门

题目描述

传智专修学院里有 \(n\) 栋教学楼,有 \(m\) 条双向通行道路连接这些教学楼,不存在重边和自环。每条道路都有一定的长度,而且所有教学楼之间都可以直接或者间接的通过道路到达。我们可以很容易的求出这些教学楼之间的最短路。

为了使交通更为顺畅,校方决定在两个教学楼里增设一对传送门。传送门可以将这对教学楼的距离直接缩短为 0。利用传送门,某些教学楼之间的最短路的距离就变短了。

由于预算有限,学校里只能安装一对传送门。但是校长希望尽可能方便学生,使任意两点之间的最短路长度的总和最小。当然啦,从 \(x\) 教学楼到 \(y\) 教学楼的长度和从 \(y\) 教学楼到 \(x\) 教学楼的长度只需要统计一次就可以了。

输入格式

输入第 1 行两个正整数 \(n,m(n\le 100,m\le\frac{1}{2}n(n-1))\),代表教学楼和道路数量。

接下来 \(m\) 行,每行三个正整数 \(x_i,y_i,w_i(0 <w_i \le 10^4)\),表示在教学楼 \(x_i\)\(y_i\) 之间,有一条长度为 \(w_i\) 的道路。

输出格式

输出一行,在最优方案下的任意点对的最短道路之和。

输入输出样例 #1

输入 #1

4 5
1 2 3
1 3 6
2 3 4
2 4 7
3 4 2

输出 #1

14

说明/提示

样例如图。当在 1 和 4 号教学楼架设一对传送门时,1 → 2 的最短路是 3,1 → 3 的最短路是 0+2,1 → 4 的最短路是 0,2 → 3 的最短路是 4,2 → 4 的最短路是 3+0,3 → 4 的最短路是 2,最短路之和是 14,是最佳方案。

解法&&个人感想

我们看到这个数据范围\(n<=100\)肯定是要用Floyd算法的 但是如果一一枚举传送门的话就会变成\(n^5\) 这个时间复杂度我们接受不了
所以 怎么办?
我们考虑上次看到的那个中转点思想 先跑一遍Floyd 然后枚举\(n^2\)的点对x,y作为传送门 对于最短路的两个起始点i,j,其距离被更新为原来最小值,i到x+y到j,i到y加x到j这三个的最小值,就将算法优化到\(n^4\)
下面我们看代码:

#include<bits/stdc++.h>
#define MAXN 105
#define MAXM 1e4+5
#define INF 1e8
#define ll long long
using namespace std;
int n,m;
int x,y,z;
int ma[MAXN][MAXN];
int tem[MAXN][MAXN];
ll res=INF;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ma[i][j]=INF;
        }
    }
    for(int i=1;i<=n;i++) ma[i][i]=0;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        ma[x][y]=z;
        ma[y][x]=z;
    }
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                ma[i][j]=min(ma[i][j],ma[i][k]+ma[k][j]);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            ll ans=0;
            for(int k=1;k<=n;k++){
                for(int v=1;v<=n;v++){
                    tem[k][v]=ma[k][v];
                }
            }
            for(int k=1;k<=n;k++){
                for(int v=1;v<=n;v++){
                    tem[k][v]=min(tem[k][v],min(tem[k][i]+tem[j][v],tem[k][j]+tem[i][v]));
                }
            }
            for(int k=1;k<=n;k++){
                for(int v=k+1;v<=n;v++){
                    ans+=tem[k][v];
                }
            }
            res=min(res,ans);
        }
    }
    printf("%lld",res);
    system("pause");
    return 0;
}
posted @ 2025-03-27 11:11  elainafan  阅读(45)  评论(0)    收藏  举报