Travel 最短路

链接:https://ac.nowcoder.com/acm/problem/14292
来源:牛客网

题目描述

精灵王国有N座美丽的城市,它们以一个环形排列在Bzeroth的大陆上。其中第i座城市到第i+1座城市花费的时间为d[i]。特别地,第N座城市到第1座城市花费的时间为d[N]。这些道路都是双向的。
另外,精灵们在数千年的时间里建造了M座传送门,第i座传送门连接了城市u[i]与城市v[i],并且需要花费w[i]的时间通过(可能有两座传送门连接了同一对城市,也有可能一座传送门连接了相同的两座城市)。这些传送门都是双向的。
小S是精灵王国交通部部长,她的职责是为精灵女王设计每年的巡查路线。每次陛下会从某一个城市到达另一个城市,沿路调查每个城市的治理情况,她需要找出一条用时最短的路线。

输入描述

第一行为2个整数N、M。
第二行为N个正整数d[i]。
接下来M行每行三个正整数u[i]、v[i]、w[i]。
第M+3行为一个正整数Q,表示需要设计路线的次数。
接下来Q行每行两个正整数x、y,表示一次从城市x到城市y的旅行。

输出描述

Q行每行一个正整数表示该次旅行的最短时间。

分析

一开始没仔细看题,直接暴力建图然后跑spfa,最后tle了。。。。

我们来分析一下这道题目,首先给了我们n个点,相邻的两个点以及首位的两个点之间连接了一条双向边,这样图中任意两个点都可以直接移动,通过的时间可以用前缀和进行计算

sum[y-1] - sum[x-1]

然后又新建了m条边m,并且m小于20,这就提醒我们,这么小的范围可以通过枚举新建的边的点,然后预处理一下这些点到所有点的距离,最后查表即可,x,y之间的距离为

d[i][x] + d[i][y]

两种移动方式取最小值即可

需要注意的是n的范围过大,如果d开二维数组可能会mle,所以可以选择将存好的点进行压缩处理

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <set>
#define debug(x) cout << #x << ':' << x << endl;
  
using namespace std;
typedef long long ll;
  
const int N = 525020,M = 3 * N;
const ll INF = 1e17;
int idx,h[N],ne[M],e[M];
ll w[M];
ll d[50][N];
bool st[N];
int n,m,q;
ll sum[N * 2];
ll a[N * 2];
set<int> S;
  
void add(int x,int y,ll z){
    e[idx] = y,w[idx] = z,ne[idx] = h[x],h[x] = idx++;
    e[idx] = x,w[idx] = z,ne[idx] = h[y],h[y] = idx++;
}
  
void spfa(int id,int s){
    for(int i = 1;i <= n;i++) d[id][i] = INF;
    d[id][s] = 0;
    queue<int>Q;
    Q.push(s);
    st[s] = true;
    while(!Q.empty()){
        int t = Q.front();
        st[t] = false;
        Q.pop();
        for(int i = h[t];~i;i = ne[i]){
            int j = e[i];
            if(d[id][j] > d[id][t] + w[i]){
                d[id][j] = d[id][t] + w[i];
                if(!st[j]){
                    Q.push(j);
                    st[j] = true;
                }
            }
        }
    }
}
  
ll cal(int x,int y){
    return y >= x ? sum[y-1] - sum[x-1] : sum[n+y-1] - sum[x-1];
}
  
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
    for(int i = n + 1;i <= n * 2;i++) a[i] = a[i - n];
    for(int i = 1;i <= 2 * n;i++) sum[i] = sum[i - 1] + a[i];
    for(int i = 1;i < n;i++) add(i,i + 1,a[i]);
    add(1,n,a[n]);
    while(m--){
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        S.insert(x);
        S.insert(y);
        add(x,y,z);
    }
    int num = 0;
    for(auto p:S) spfa(num++,p);
    scanf("%d",&q);
    while(q--){
        int x,y;
        scanf("%d%d",&x,&y);
        ll ans = min(cal(x,y),cal(y,x));
        num = 0;
        for(auto p:S){
            ans = min(ans,d[num][x] + d[num][y]);
            num++;
        }
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/tlyzxc/article/details/107731381