【洛谷】P1119 灾后重建

  • Post author:
  • Post category:其他




题目地址:


https://www.luogu.com.cn/problem/P1119

题目背景:

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

题目描述:

给出B地区的村庄数



N

N






N





,村庄编号从



0

0






0









N

1

N-1






N













1





,和所有



M

M






M





条公路的长度,公路是双向的。并给出第



i

i






i





个村庄重建完成的时间



t

i

t_i







t










i





















,你可以认为是同时开始重建并在第



t

i

t_i







t










i





















天重建完成,并且在当天即可通车。若



t

i

t_i







t










i

























0

0






0





则说明地震未对此地区造成损坏,一开始就可以通车。之后有



Q

Q






Q





个询问



(

x

,

y

,

t

)

(x,y,t)






(


x


,




y


,




t


)





,对于每个询问你要回答在第



t

t






t





天,从村庄



x

x






x





到村庄



y

y






y





的最短路径长度为多少。如果无法找到从



x

x






x





村庄到



y

y






y





村庄的路径,经过若干个已重建完成的村庄,或者村庄



x

x






x





或村庄



y

y






y





在第



t

t






t





天仍未重建完成,则需要输出



1

-1









1





输入格式:

第一行包含两个正整数



N

,

M

N,M






N


,




M





,表示了村庄的数目与公路的数量。

第二行包含



N

N






N





个非负整数



t

0

,

t

1

,


,

t

N

1

t_0,t_1,\cdots,t_{N-1}







t










0


















,





t










1


















,











,





t











N





1






















,表示了每个村庄重建完成的时间,数据保证了



t

0

t

1

t

N

1

t_0\le t_1\le \cdots \le t_{N-1}







t










0






























t










1












































t











N





1
























接下来



M

M






M





行,每行



3

3






3





个非负整数



i

,

j

,

w

i,j,w






i


,




j


,




w









w

w






w





为不超过



10000

10000






10000





的正整数,表示了有一条连接村庄



i

i






i





与村庄



j

j






j





的道路,长度为



w

w






w





,保证



i

j

i\neq j






i
























=









j





,且对于任意一对村庄只会存在一条道路。

接下来一行也就是



M

+

3

M+3






M




+








3





行包含一个正整数



Q

Q






Q





,表示



Q

Q






Q





个询问。

接下来



Q

Q






Q





行,每行



3

3






3





个非负整数



x

,

y

,

t

x,y,t






x


,




y


,




t





,询问在第



t

t






t





天,从村庄



x

x






x





到村庄



y

y






y





的最短路径长度为多少,数据保证了



t

t






t





是不下降的。

输出格式:





Q

Q






Q





行,对每一个询问



(

x

,

y

,

t

)

(x,y,t)






(


x


,




y


,




t


)





输出对应的答案,即在第



t

t






t





天,从村庄



x

x






x





到村庄



y

y






y





的最短路径长度为多少。如果在第



t

t






t





天无法找到从



x

x






x





村庄到



y

y






y





村庄的路径,经过若干个已重建完成的村庄,或者村庄



x

x






x





或村庄



y

y






y





在第



t

t






t





天仍未修复完成,则输出



1

-1









1





数据范围:

对于



30

30%






30





的数据,有



N

50

N\le50






N













50







对于



30

30%






30





的数据,有



t

i

=

0

t_i=0







t










i




















=








0





,其中有



20

20%






20





的数据有



t

i

=

0

t_i=0







t










i




















=








0









N

>

50

N>50






N




>








50







对于



50

50%






50





的数据,有



Q

100

Q\le100






Q













100







对于



100

100%






100





的数据,有



1

N

200

1\le N\le200






1













N













200









0

M

N

×

(

N

1

)

2

0\le M\le\dfrac{N\times(N-1)}{2}






0













M
























2














N




×




(


N









1


)



























1

Q

50000

1\le Q\le50000






1













Q













50000





,所有输入数据涉及整数均不超过



1

0

5

10^5






1



0










5












回忆一下Floyd算法

https://blog.csdn.net/qq_46105170/article/details/113821689

,其可以算出只经过村庄



0

k

0\sim k






0













k





中转的所有点对的最短路(“中转”的意思是不包括起点和终点)。那么我们要回答询问,只需要先求出询问的时间的那一刻,哪些村庄已经建好,然后按Floyd算法一路递推到最后修好的村庄即可。由于题目里的村庄是按编号修好的,询问的时间也是递增的,所以可以按



0

,

1

,

.

.

.

0,1,…






0


,




1


,










的顺序递推。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 210, INF = 0x3f3f3f3f;
int n, m;
int tm[N];
int g[N][N];

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

int main() {
  memset(g, 0x3f, sizeof g);
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++) {
    scanf("%d", &tm[i]);
    g[i][i] = 0;
  }
  for (int i = 0; i < m; i++) {
    int a, b, w;
    scanf("%d%d%d", &a, &b, &w);
    g[a][b] = g[b][a] = min(g[a][b], w);
  }

  int Q;
  scanf("%d", &Q);
  int cur_city = 0;
  while (Q--) {
    int a, b, t;
    scanf("%d%d%d", &a, &b, &t);
    while (tm[cur_city] <= t && cur_city < n) update(cur_city++);

	// 这里需要额外判断一下起点和终点有没有修好
    printf("%d\n",
           a < cur_city && b < cur_city && g[a][b] < INF ? g[a][b] : -1);
  }
}

总时间复杂度



O

(

n

3

)

O(n^3)






O


(



n










3









)





,空间



O

(

n

2

)

O(n^2)






O


(



n










2









)







版权声明:本文为qq_46105170原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。