【题解】洛谷P1119 灾后重建

前往:我自己搭建的博客

题目

洛谷P1119灾后重建

题解

由于询问数Q比较大,不可能每次询问都新建图,所以考虑离线(集中处理询问)。注意到村庄重建时间是不严格递增的,所以在时间t[i]之前,只有编号为0~i的村庄重建完。注意到村庄数n比较小,可以考虑floyd算法,这个算法可以求出任意两点间的最短路,同时,在动态规划过程中,floyd算法也解决了“若只经过编号为0~i的节点,求任意两点间的最短路径”这个子问题。所以,在执行floyd算法的同时,更新符合当前条件的询问的答案。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=200+5;
const int maxq=5e4+5;
int n,m,q;
int d[maxn][maxn],ti[maxn];
struct question{int x,y,t,ans;}a[maxq];
inline void floyd()
{
	for(int i=0;i<n;i++) d[i][i]=0;
	for(int k=0;k<n;k++)
	{
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
		for(int i=q;i>=1&&ti[k]<=a[i].t;i--) 
			if(a[i].x<=k&&a[i].y<=k) a[i].ans=min(a[i].ans,d[a[i].x][a[i].y]);	 
	}	//注意floyd算法在第k轮求出的d[][],并不能保证路径的起点和终点属于编号为0~k的节点 
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%d",&ti[i]);
	memset(d,0x3f,sizeof(d));
	for(int i=1;i<=m;i++) 
	{
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		d[x][y]=d[y][x]=z;
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t),a[i].ans=inf;
	floyd();
	for(int i=1;i<=q;i++) 
	{
		if(a[i].ans==inf) printf("-1\n");
		else printf("%d\n",a[i].ans);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zjgmartin/article/details/108415420