【题解】P1119 灾后重建

我感觉这道题的思路十分巧妙,巧妙地利用了 \(Floyd\) 的思想,来做出这道题,不得不说, \(A\) 掉了这题以后,我感觉自己对 \(Floyd\) 的实质了解了更多。

思路

事实上,我们都知道 \(Floyd\) 的标准代码长这样

for(int k=1;k<=n;++k)  
  for(int i=1;i<=n;++i)  
    for(int j=1;j<=n;++j)  
      f[i][j]=min(f[i][j],f[i][k]+f[k][j]);  

那么对于这道题,对于每一个村庄,我们都有一个时间 \(time_i\) ,只有每条路线相连的两个村庄修好的时间恰好小于等于当前询问的时间(注:询问的时间是保证单调递增的),这条路线才是有效的。
对于每一个修好的村庄 \(i\) ,我们可以将所有连着 \(i\) 村庄的村庄的最短路更新一遍,代码实现为

void update(int k)
{
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			f[i][j]=f[j][i]=min(f[i][j],f[i][k]+f[k][j]);
}

没错,跟普通的 \(Floyd\) 是大致一样的,只不过是我们给出了单独更新的 \(k\)
\(Code:\)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int tot,n,m;
int t[211],f[211][211];
bool book[211];
void update(int k)
{
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			f[i][j]=f[j][i]=min(f[i][j],f[i][k]+f[k][j]);
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int inf=1e9;
	scanf("%d %d",&n,&m);
	for(int i=0;i<n;++i) scanf("%d",&t[i]);
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)	
			f[i][j]=inf;
	for(int i=1;i<=m;++i)
	{
		int u,v,w;
		scanf("%d %d %d",&u,&v,&w);
		f[u][v]=f[v][u]=w;
	}
	int Q,now=0;
	scanf("%d",&Q);
	for(int i=1;i<=Q;++i)
	{
		int x,y,ta;
		scanf("%d %d %d",&x,&y,&ta);
		while(t[now]<=ta && now<n)
		{
			book[now]=true; 
			update(now);		
			++now;
		}
		if(t[x]>ta || t[y]>ta || f[x][y]==inf) printf("-1\n");
		else printf("%d\n",f[x][y]);
	}
	return 0;
}
posted @ 2019-08-07 16:31  zhz小蒟蒻  阅读(104)  评论(0编辑  收藏  举报