洛谷1119 图论

来源:互联网 发布:淘宝店铺显示的是昵称 编辑:程序博客网 时间:2024/06/04 01:08

题目大意:村庄受损道路完好。
给出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。

这道题与常见的灾后重建有类似又有不同:常见的灾后重建是村庄完好重建道路,往往是跑最短路或最小生成树的模板,但此题是村庄受损道路完好,想到与点关系密切的最短路算法就只有floyd.再看这道题的N只有200,更加肯定了是floyd。

思路是:对于每个询问,去依次枚举这个询问前恢复了的每个点。
这题和Floyd模板不同的是用了2个数组,g[][]和dis[][]来跑floyd,因为对于每个询问,恢复的点都不同,dis[a][b]表示当前这个询问时a到b的最短路程,而g[a][b]表示若所有点都可用时a到b的最短路程。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxn = 100;const int inf = 0x3f3f3f3f;int dis[202][202],t[202],n,m,q,x,y,ti,a,b,w,g[202][202];int main(){    memset(dis,inf,sizeof(dis));    memset(g,inf,sizeof(g));    scanf("%d%d",&n,&m);    for(int i = 0; i < n; ++i)  scanf("%d",&t[i]);    for(int i = 1; i <= m; ++i)     {        scanf("%d%d%d",&a,&b,&w);        g[a][b] = g[b][a] = w;    }    sort(t, t + n);    for(int i = 0; i < n; ++i) g[i][i] = 0;    scanf("%d",&q);    for(int i = 1,j = 0; i <= q; ++i)    {        scanf("%d%d%d",&x,&y,&ti);        while(t[j] <= ti && j < n)        {               for(int a = 0; a < n; ++a)                for(int b = 0; b < n; ++b)                if(a != b)                {                    g[a][b] = min(g[a][b],g[a][j] + g[j][b]);                    if(t[a] <= ti && t[b] <= ti)                    {                        dis[a][j] = min(g[a][j],dis[a][j]);dis[j][b] = min(dis[j][b],g[j][b]);                        dis[a][b] = min(dis[a][b],dis[a][j] + dis[j][b]);                    }                }            ++j;        }        if(dis[x][y] == inf) printf("-1\n");        else printf("%d\n",dis[x][y]);      }    return 0;}
原创粉丝点击