【2020.2.7 练习赛】 T5-道路开通/灾后重建(图论-Floyd)

来源:JZOJ,Luogu P1119 灾后重建

题目描述-原题

B B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。

改版

疫情导致很多城市的公路都封掉了。

现在疫情开始没那么严峻, z j zj 省的高速公路开始慢慢恢复。

现在设 z j zj 省的城市有 N N 个,有 M M 条双向公路相连,每条公路有相应的长度。

现在给出第 i i 个城市公路开通的时间 t [ i ] t[i]

当然如果 t [ i ] t[i] 0 0 ,表示第i个城市就没有封锁。

现在指挥部要知道道路运行情况,有 S S 次询问,询问格式为 s t e n q (st,en,q)

每个询问表示从 s t st 号城市到 e n en 城市,在第 q q 天是否可以到达,如果可以到达,请给出最短的长度,如果不可以到达,输出 1 -1

解题思路

  • 这是一道深入 F l o y d Floyd 本质的题目,首先得先了解一下 F l o y d Floyd ,这短小精悍的算法:通过其他中转点求任意两点之间的最短路,丢代码;
for(k=1;k<=n;k++)
  for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
      dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
  • 这段代码能否和本题联系起来呢?
  • 思路如下:按时间顺序找到每一个在 q q 天之内能修好的点,作为中转点,暴力 F l o y d Floyd 即可
  • 不过,这样是会 T L E TLE 的,我们需要加一个小优化,就是用一个 v i s vis 数组标记, v i s [ i ] vis[i] 表示 i i 是否做过中转点,这样就可以 A C AC

C o d e Code

#pragma GCC optimize ("O2")  //err... 手动开O2...罒ω罒
#pragma G++ optimize ("O2") 
#include <bits/stdc++.h>
#define Inf 0x3fffffff
using namespace std;
bool vis[210];
int a[210][210],t[210];
inline int read()  //快读
{
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int main()
{
	freopen("rebuild.in","r",stdin);
	freopen("rebuild.out","w",stdout);
	int n=read(),m=read();
	for (register int i=0;i<n;i++) t[i]=read();
	for (register int i=0;i<n;i++)  //手动赋值正无穷(邻接矩阵)
     for (register int j=0;j<n;j++)
      a[i][j]=Inf;
    for (register int i=0;i<n;i++) a[i][i]=0;  //i点到i点距离为0
	for (register int i=1;i<=m;i++)
	{
		int x=read(),y=read(),v=read();
		a[x][y]=a[y][x]=v;  //赋初值
	}
	int q;
	q=read();
	for (register int I=1;I<=q;I++)  //q次询问
	{
		int st=read(),en=read(),time=read();
		int k=0;
		for (register int k=0;k<n;k++)
		{
			if (t[k]<=time && !vis[k])  //找到没有用过且在q天之内能修好的点
			{
				vis[k]=1;  //标记
				for (register int i=0;i<n;i++)
		  	 	 for (register int j=0;j<n;j++)
		  	  	  a[i][j]=min(a[i][j],a[i][k]+a[k][j]);  //Floyd更新距离
			}
		}
		if (t[st]>time || t[en]>time || a[st][en]>=Inf) printf("-1\n");  //不合法
		else printf("%d\n",a[st][en]);
	}
	return 0;
}
发布了28 篇原创文章 · 获赞 33 · 访问量 2156

猜你喜欢

转载自blog.csdn.net/qq_43081996/article/details/104250292