CODEVS 1817 灾后重建 Label:Floyd || 最短瓶颈路

描述

灾后重建(rebuild) 
  B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。 
  给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间t[i],你可以认为是同时开始重建并在第t[i]天重建完成,并且在当天即可通车。若t[i]为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。 

输入格式

  输入文件rebuild.in的第一行包含两个正整数N,M,表示了村庄的数目与公路的长度。 
  第二行包含N个非负整数t[0], t[1], …, t[N – 1],表示了每个村庄重建完成的时间,数据保证了t[0] ≤ t[1] ≤ … ≤ t[N – 1]。 
  接下来M行,每行3个非负整数i, j, w,w为不超过10000的正整数,表示了有一条连接村庄i与村庄j的道路,长度为w,保证i≠j,且对于任意一对村庄只会存在一条道路。 
  接下来一行也就是M+3行包含一个正整数Q,表示Q个询问。 
  接下来Q行,每行3个非负整数x, y, t,询问在第t天,从村庄x到村庄y的最短路径长度为多少,数据保证了t是不下降的。 

输出格式

  输出文件rebuild.out包含Q行,对每一个询问(x, y, t)输出对应的答案,即在第t天,从村庄x到村庄y的最短路径长度为多少。如果在第t天无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未修复完成,则输出-1。 

测试样例1

输入

4 5 
1 2 3 4 
0 2 1 
2 3 1 
3 1 2 
2 1 4 
0 3 5 

2 0 2 
0 1 2 
0 1 3 
0 1 4 

输出

-1 
-1 

备注

【数据规模】 
  对于30%的数据,有N≤50; 
  对于30%的数据,有t[i] = 0,其中有20%的数据有t[i] = 0且N>50; 
  对于50%的数据,有Q≤100; 
  对于100%的数据,有N≤200,M≤N*(N-1)/2,Q≤50000,所有输入数据涉及整数均不超过100000。 

代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int n,m,point=0;
 8 int T[505],g[505][505],note[505];//下标从0开始 
 9 
10 void init_(){
11     memset(g,-1,sizeof(g));
12     scanf("%d%d",&n,&m);
13     
14     for(int i=0;i<n;i++){
15         scanf("%d",&T[i]);
16         if(T[i]==0) note[i]=1,point=i;
17     }
18     for(int i=1;i<=m;i++){
19         int x,y,w;
20         scanf("%d%d%d",&x,&y,&w);
21         g[x][y]=w;
22         g[y][x]=w;
23     }
24 }
25 
26 void floyd(int x){
27     point=x+1,note[x]=1;
28 
29     for(int i=0;i<n;i++){//更新到x的距离
30         for(int j=0;j<n;j++){
31             if(note[i] && note[j] && g[i][j]!=-1 && g[j][x]!=-1){
32                 if(g[i][j]+g[j][x]<g[i][x] || g[i][x]==-1){
33                     g[x][i]=g[i][x]=g[i][j]+g[j][x];
34                 }        
35             }
36         }
37     }
38     
39     for(int i=0;i<n;i++){//更新以x为中继的点
40         for(int j=0;j<n;j++){
41             if(note[i] && note[j] && g[i][x]!=-1 && g[x][j]!=-1){
42                 if(g[i][x]+g[x][j]<g[i][j] || g[i][j]==-1){
43                     g[i][j]=g[i][x]+g[x][j];
44                 }
45             }
46         }
47     }
48 }
49 
50 
51 void solve(){
52     int x,y,t,ask;
53     scanf("%d",&ask);
54     
55     if(point!=0){//对T[i]=0的点先进行最短路
56         for(int k=0;k<=point;k++)
57             for(int i=0;i<=point;i++)
58                 for(int j=0;j<=point;j++)
59                     if(g[i][k]!=-1 && g[k][j]!=-1)
60                         if(g[i][k]+g[k][j]<g[i][j] || g[i][j]==-1)
61                             g[i][j]=g[i][k]+g[k][j];
62     }
63     
64     while(ask--){
65         scanf("%d%d%d",&x,&y,&t);
66         while(t>=T[point] && point<n) floyd(point);
67         if( note[x] && note[y] ) printf("%d
",g[x][y]);
68         else puts("-1");
69     }
70 }
71 
72 int main(){
73 //  freopen("01.in","r",stdin);
74     init_();
75     solve();
76     return 0;
77 }

不知道为什么洛谷过不了,TYVJ 和 CODEVS 都可以过

当然可以在线floyd,O(n^4),可以过4个点(我是不会说我之前就是这么做的)

转个题解:

数据规模比较小,所以用矩阵+离线floyd(在线spfa貌似要超时)

floyd算法中枚举的k是中转点,在这道题中就可以按时间顺序把点当作中转点,挨个儿加入图中,并且同时将‘时间恰当的询问’求出来(是指询问的时间<=t[k]的询问)

﹡注意题中所给的数据已经排好了序

最小瓶颈路:

题目大意:有一些村庄与它们之间的通路(即是图中的顶点和边),每条通路都有一个修复时间,要求何时所有村庄都可以连通。

其实就是一个无向带权图,要求最小瓶颈生成树(这棵树的边的最大值为这棵树的值)。可以用prim算法与kruskal算法。也可以用dijkstra算法。

为什么可以用dijkstra算法?首先,所有边权值非负。然后可以发现,当两个村庄相通时,它们的最短路(指的是瓶颈最短路)即为它们相通的最短时间,因为它们相通的条件是存在某几条修好的公路将它们连接,于是时间就取决于这几条公路中最迟建好的那条,于是把时间看成权,任意取一个顶点,使用DJ算法,求得他到其他所有公路的最短瓶颈路(最短时间内两村庄通车),因为是无向图,所以A到B的最短路即为B到A的最短路。于是源与其他所有顶点最短路的最大值即为所求。

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!
原文地址:https://www.cnblogs.com/radiumlrb/p/5858676.html