题目背景
B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
题目描述
给出 B 地区的村庄数 NN,村庄编号从 0 到 N−1,和所有 MM 条公路的长度,公路是双向的。并给出第 i 个村庄重建完成的时间 ti,你可以认为是同时开始重建并在第 ti 天重建完成,并且在当天即可通车。若 ti 为 0 则说明地震未对此地区造成损坏,一开始就可以通车。之后有 Q 个询问 (x,y,t),对于每个询问你要回答在第 t 天,从村庄 x 到村庄 y 的最短路径长度为多少。如果无法找到从 x 村庄到 y 村庄的路径,经过若干个已重建完成的村庄,或者村庄 x 或村庄 y 在第 t天仍未重建完成,则需要返回
-1
。输入格式
第一行包含两个正整数N,M,表示了村庄的数目与公路的数量。
第二行包含N个非负整数t0,t1,…,tN−1,表示了每个村庄重建完成的时间,数据保证了t0≤t1≤…≤tN−1。
接下来M行,每行3个非负整数i,j,w,w为不超过10000的正整数,表示了有一条连接村庄ii与村庄jj的道路,长度为w,保证i≠j,且对于任意一对村庄只会存在一条道路。
接下来一行也就是M+3行包含一个正整数Q,表示Q个询问。
接下来Q行,每行3个非负整数x,y,t,询问在第tt天,从村庄x到村庄y的最短路径长度为多少,数据保证了t是不下降的。
输出格式
共Q行,对每一个询问(x,y,t)输出对应的答案,即在第t天,从村庄x到村庄y的最短路径长度为多少。如果在第t天无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未修复完成,则输−1。
输入输出样例
输入 #1复制
4 5 1 2 3 4 0 2 1 2 3 1 3 1 2 2 1 4 0 3 5 4 2 0 2 0 1 2 0 1 3 0 1 4输出 #1复制
-1 -1 5 4说明/提示
对于30%的数据,有N≤50N≤50;
对于30%的数据,有t_i= 0ti=0,其中有20\%20%的数据有t_i = 0ti=0且N>50N>50;
对于50%的数据,有Q≤100Q≤100;
对于100%的数据,有N≤200,M≤N×(N−1)/2,Q≤50000,所有输入数据涉及整数均不超过100000。
dijkstra求解,超时,o2优化可以过
#include <iostream>
#include <utility>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int>PII;
int n,m,tim[205],dist[205];
vector<PII>adj[20010];
bool vis[205];
int dijkstra(int x,int y,int t){
if(tim[x]>t||tim[y]>t) return -1;
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis));
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push(make_pair(0,x));
dist[x]=0;
while(!q.empty()){
auto it=q.top();
q.pop();
int ver=it.second;
if(vis[ver]) continue;
vis[ver]=1;
for(const auto &[j,w]:adj[ver]){
if (dist[j] > dist[ver] + w) {
dist[j] = dist[ver] + w;
if(tim[j]<=t){
q.push(make_pair(dist[j],j));
}
}
}
}
if(dist[y]==0x3f3f3f3f) return -1;
return dist[y];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&tim[i]);
}
for(int i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
adj[u].push_back(make_pair(v,w));
adj[v].push_back(make_pair(u,w));
}
int z;
scanf("%d",&z);
while(z--){
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
printf("%d\n",dijkstra(x,y,t));
}
}
floyd,可以过 ,这道题很良心,时间是按照顺序,Q次询问也是按照时间不降,所以省去了很多麻烦
#include<iostream>
#include<cstdio>
#define N 205
using namespace std;
int n,m;
int a[N];
int f[N][N];
void updata(int k){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[j][k])
f[i][j]=f[j][i]=f[i][k]+f[j][k];
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
scanf("%d",a+i);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
f[i][j]=1e9;
}
for(int i=0;i<n;i++)
f[i][i]=0;
int s1,s2,s3;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&s1,&s2,&s3);
f[s1][s2]=f[s2][s1]=s3;
}
int q;
cin>>q;
int now=0;
for(int i=1;i<=q;i++){
scanf("%d%d%d",&s1,&s2,&s3);
while(a[now]<=s3&&now<n){
updata(now);
now++;
}
if(a[s1]>s3||a[s2]>s3)cout<<-1<<endl;
else {
if(f[s1][s2]==1e9)cout<<-1<<endl;
else cout<<f[s1][s2]<<endl;
}
}
return 0;
}