[洛谷P1119][codevs1817]灾后重建

题目大意:有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();
    }
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7761075.html