题目:https://www.nowcoder.com/acm/contest/17/B
题意:
题目描述
精灵王国有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行每行一个正整数表示该次旅行的最短时间。
wls的题解:
通过一些观察可得:节点 u 到节点 v 的最短路肯定为以下两种情况之一: 1、不经过额外的 m 条边直接从 u 到 v。
2、从 u 先走到某个为额外边端点的 x,再从 x 走到某个同样为额外边端点的 y,最后从
y 走到 v。
预处理所有额外边的端点间两两最短路,询问时暴力枚举 x、y 更新答案即可。
时间复杂度:O(M3 +N+Q× M3)。
代码:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN=100005;
const int MAXM=25;
const ll INF=(1LL<<60)-1;
int u[MAXM],v[MAXM],key[MAXM<<1];
ll d[MAXN],p[MAXN],w[MAXM];
vector<pair<int,ll> > e[MAXN];
ll dis[MAXM<<1][MAXN];
void Dijkstra(int id,int n)
{
int st=key[id];
for(int i=1;i<=n;i++)
dis[id][i]=INF;
priority_queue<pair<ll,int> > pq;
pq.push(make_pair(dis[id][st]=0,st));
while(!pq.empty())
{
int u=pq.top().second;
pq.pop();
for(int j=0;j<e[u].size();j++)
{
pair<ll,int> t=e[u][j];
int v=t.first,c=t.second;
if(dis[id][v]>dis[id][u]+c)
{
dis[id][v]=dis[id][u]+c;
pq.push(make_pair(-dis[id][v],v));
}
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&d[i]);
e[i].push_back(make_pair(i%n+1,d[i]));
e[i%n+1].push_back(make_pair(i,d[i]));
}
for(int i=1;i<=n;i++)
p[i]=p[i-1]+d[i];
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld",&u[i],&v[i],&w[i]);
e[u[i]].push_back(make_pair(v[i],w[i]));
e[v[i]].push_back(make_pair(u[i],w[i]));
}
int c=0;
for(int i=1;i<=m;i++)
key[++c]=u[i],key[++c]=v[i];
sort(key+1,key+c+1);
c=unique(key+1,key+c+1)-(key+1);
for(int i=1;i<=c;i++)
Dijkstra(i,n);
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ll len=abs(p[x-1]-p[y-1]);
ll res=min(len,p[n]-len);
for(int j=1;j<=c;j++)
res=min(res,dis[j][x]+dis[j][y]);
printf("%lld\n",res);
}
return 0;
}