• 灾后重建(洛谷P1119,图论floyd)


                                                         P1119 灾后重建

    题目背景

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

    题目描述

    给出BBB地区的村庄数NNN,村庄编号从000到N−1N-1N1,和所有MMM条公路的长度,公路是双向的。并给出第iii个村庄重建完成的时间tit_iti,你可以认为是同时开始重建并在第tit_iti天重建完成,并且在当天即可通车。若tit_iti000则说明地震未对此地区造成损坏,一开始就可以通车。之后有QQQ个询问(x,y,t)(x, y, t)(x,y,t),对于每个询问你要回答在第ttt天,从村庄xxx到村庄y的最短路径长度为多少。如果无法找到从xxx村庄到yyy村庄的路径,经过若干个已重建完成的村庄,或者村庄xxx或村庄yyy在第t天仍未重建完成 ,则需要返回−1-11。

    输入格式

    第一行包含两个正整数N,MN,MN,M,表示了村庄的数目与公路的数量。

    第二行包含NNN个非负整数t0,t1,…,tN−1t_0, t_1,…, t_{N-1}t0,t1,,tN1,表示了每个村庄重建完成的时间,数据保证了t0≤t1≤…≤tN−1t_0 ≤ t_1 ≤ … ≤ t_{N-1}t0t1tN1

    接下来MMM行,每行333个非负整数i,j,wi, j, wi,j,w,www为不超过100001000010000的正整数,表示了有一条连接村庄iii与村庄jjj的道路,长度为www,保证i≠ji≠ji=j,且对于任意一对村庄只会存在一条道路。

    接下来一行也就是M+3M+3M+3行包含一个正整数QQQ,表示QQQ个询问。

    接下来QQQ行,每行333个非负整数x,y,tx, y, tx,y,t,询问在第ttt天,从村庄xxx到村庄yyy的最短路径长度为多少,数据保证了ttt是不下降的。

    输出格式

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

    输入输出样例

    输入 #1
    4 5
    1 2 3 4
    0 2 1
    2 3 1
    3 1 2
    2 1 4
    0 3 5
    4
    2 0 2
    0 1 2
    0 1 3
    0 1 4
    输出 #1
    -1
    -1
    5
    4

    说明/提示

    对于30%30\%30%的数据,有N≤50

    对于30%30\%30%的数据,有ti=0t_i= 0ti=0,其中有20%20\%20%的数据有ti=0N>50

    对于50%50\%50%的数据,有Q≤100

    对于100%100\%100%的数据,有N≤200M≤N×(N−1)/2,Q<=50000,所有输入数据涉及整数均不超过100000100000100000。

    思路:非常好的floyd练习题,因为这道题我加深了对floyd本质的认识;

    1 for(int k=1;k<=n;k++){
    2     for(int i=1;i<=n;i++){
    3         for(int j=1;j<=n;j++){
    4             f[i][j]=f[i][k]+f[k][j];
    5         }
    6     }
    7 }

    floyd本质:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。

    这也是此题的关键思路。

    下面是代码(有详解)

     1 #include<cstdio>
     2 const int maxn=200+10,inf=0x3f3f3f3f;
     3 int a[maxn],w[maxn][maxn],f[maxn][maxn];
     4 int n;
     5 void Init(){
     6     for(int i=0;i<n;i++){
     7         for(int j=0;j<n;j++){
     8             f[i][j]=inf;
     9         }
    10     }
    11     for(int i=0;i<n;i++) f[i][i]=0;
    12 }
    13 void work(int k){
    14     for(int i=0;i<n;i++){
    15         for(int j=0;j<n;j++){
    16             if(f[i][j]>f[i][k]+f[k][j]) f[i][j]=f[i][k]+f[k][j];
    17         }
    18     }
    19 }
    20 int main(){
    21     int m;
    22     scanf("%d%d",&n,&m);
    23     for(int i=0;i<n;i++) scanf("%d",&a[i]);//读入每个村庄修建好时间(因为按顺序给出,所以不用先记录在排序)
    24     Init();//初始化(普通的floyd)
    25     for(int i=1;i<=m;i++){
    26         int x,y,z;
    27         scanf("%d%d%d",&x,&y,&z);
    28         f[x][y]=f[y][x]=z;//初始化(普通的floyd)
    29     }
    30     int q;
    31     scanf("%d",&q);
    32     int last=0;
    33     for(int i=1;i<=q;i++){
    34         int x,y,t;
    35         scanf("%d%d%d",&x,&y,&t);//读入每个询问
    36         if(a[x]>t||a[y]>t){
    37             printf("-1
    ");
    38             continue;
    39         }//如果x或y未修建好,直接输出-1
    40         int j;
    41         for(j=last;j<n;j++){
    42             if(a[j]>t) break;
    43             work(j);
    44         }//寻找在t之前修好的且没有用过他来松弛的村庄来松弛,结合之前的初始化,开始时给f数组附上了一些值,不用担心这会影响结果,因为x,y在t或t之前被修好的
    45         last=j;//所以j更新t以后的对答案无太大影响,且刚好他更新完了后边的,这就是floyd算法,所以之前的x或y是否修建好的判断一定要有,不然若j更新了,答案会错
    46         if(f[x][y]==inf) printf("-1
    ");
    47         else printf("%d
    ",f[x][y]);
    48     }
    49     return 0;
    50 }
    View Code
  • 相关阅读:
    hdu 2822 Dogs (BFS+优先队列)
    hdu 2757 Ocean Currents(BFS+DFS)
    hdu2844 Coins(普通的多重背包 + 二进制优化)
    hdu1495 && pku3414
    hdu1054 Strategic Game(树形DP)
    FckEditor V2.6 fckconfig.js中文注释
    数字文本控件
    统计在线用户列表 for .net WebForm
    智能客户端
    模拟Confirm的Web自定义控件
  • 原文地址:https://www.cnblogs.com/HZOIDJ123/p/13423054.html
Copyright © 2020-2023  润新知