题目大意:有n个村庄和一些连通两个村庄的双向道路。每个村庄在一个特定的时间修复。没有修复的村庄不能经过。现在有一系列询问,问两个村庄在t时刻的最短路(如果无法到达或两个村庄本身未修复,输出-1)。
解题思路:村庄数量少,可以考虑floyd。
但询问与时间有关,不同时间内最短路是不同的,那么对每个询问都跑一遍最短路?$O(qn^3)$的时间复杂度一定会超时。
不过我们可以发现,如果t1~t2时间段内,没有任何修改,就不必每次跑一遍最短路。
而且,floyd第一重循环是枚举中间点的,那我们按照修复时间从小到大枚举中间点,然后进行后两重循环,就能保证此次循环后的状态是修复了这个村庄后,而后面的村庄还未修复时的状态。
然后在这中间处理询问即可。
这样做相当于只跑了一遍floyd就处理完了询问,所以总时间复杂度$O(q+n^3)$,即可通过此题。
C++ Code:
#include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; int n,m,dis[202][202],tm[202]; struct sj{ int t,num; bool operator<(const sj& rhs)const{return t<rhs.t;} }p[202]; inline int readint(){ char c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } int main(){ n=readint(),m=readint(); for(int i=0;i<n;++i) p[i]=(sj){tm[i]=readint(),i}; sort(p,p+n); memset(dis,0x3f,sizeof dis); while(m--){ int x=readint(),y=readint(),z=readint(); dis[x][y]=dis[y][x]=z; } m=readint(); int now=1,x=readint(),y=readint(),t=readint(); p[n].t=0x3f3f3f3f; for(int f=0;;++f){ int k=p[f].num; while(p[f].t>t){ if(tm[x]>t||tm[y]>t||dis[x][y]==0x3f3f3f3f)puts("-1");else printf("%d ",dis[x][y]); if(++now>m)return 0; x=readint(),y=readint(),t=readint(); } if(f==n)return 0; for(int i=0;i<n;++i) if(i!=k) for(int j=0;j<n;++j) if(i!=j&&j!=k&&dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; } return 0; }
由于洛谷支持Java了,我又写了个Java的代码,比较丑陋,而且时间也极慢。但还是能过去的。
Java Code:
import java.io.*; import java.util.*; public class Main{ public static void main(String[] args)throws IOException{ StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out)); in.nextToken(); int n=(int)in.nval,m,tm[]=new int[202],tm2[]=new int[202],dis[][]=new int[202][202],nb[]=new int[202]; in.nextToken(); m=(int)in.nval; for(int i=0;i<n;++i) for(int j=0;j<n;++j)dis[i][j]=0x3f3f3f3f; for(int i=0;i<n;++i){ in.nextToken(); tm[i]=tm2[i]=(int)in.nval; nb[i]=i; } for(int i=0;i<n;++i) for(int j=i+1;j+1<n;++j) if(tm[i]>tm[j]){ int t=tm[i]; tm[i]=tm[j]; tm[j]=t; t=nb[i]; nb[i]=nb[j]; nb[j]=t; } while(m!=0){ --m; int x,y,z; in.nextToken(); x=(int)in.nval; in.nextToken(); y=(int)in.nval; in.nextToken(); z=(int)in.nval; dis[x][y]=dis[y][x]=z; } in.nextToken(); m=(int)in.nval; int x,y,t,now=1; in.nextToken();x=(int)in.nval; in.nextToken();y=(int)in.nval; in.nextToken();t=(int)in.nval; tm[n]=0x3f3f3f3f; for(int p=0;;++p){ int k=nb[p]; while(tm[p]>t){ if(tm2[x]>t||tm2[y]>t||dis[x][y]==0x3f3f3f3f) out.println(-1);else out.println(dis[x][y]); ++now; if(now>m){ out.close(); return; } in.nextToken();x=(int)in.nval; in.nextToken();y=(int)in.nval; in.nextToken();t=(int)in.nval; } if(p==n)break; for(int i=0;i<n;++i) if(i!=k) for(int j=0;j<n;++j) if(i!=j&&j!=k&&dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; } out.close(); } }