链接: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);
}
}