HDU 3631 Shortest Path (Floyd的深层理解)

来源:互联网 发布:java实验指导书答案 编辑:程序博客网 时间:2024/03/29 19:38

题目链接:点击打开链接

题目大意:有一张有向图,300个点,然后有10^5次操作,操作有两种,一种是激活某一个点,另一种是询问两个点之间的最短路径,这条路径必须由被激活的点构成。

显然任意两点之间的距离理想的是floyd。

这题让我对floyd有了更深的理解,以前一直觉得floyd非常好写,但是对于其原理一知半解,在这个变形应用里就遇到了困难。

我最开始非常原始的想法就是,如果floyd里加入一个点,多出来的运算如何表述。写了一发,只是找规律,没有理解其精髓。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;#define inf 0x3f3f3f3fint dis[305][305];bool vis[305];int mark[305],nn,n,m,q;int main(){    int u,v,len,op,cas = 1;    while(~scanf("%d%d%d",&n,&m,&q)){        if(n==0&&m==0&&q==0) break;        if(cas > 1) printf("\n");        printf("Case %d:\n",cas++);        nn = 0;        memset(dis,0x3f,sizeof(dis));        memset(vis,0,sizeof(vis));        for(int i = 0;i < n; i++) dis[i][i] = 0;        for(int i = 0;i < m; i++){            scanf("%d%d%d",&u,&v,&len);            dis[u][v] = min(len,dis[u][v]);        }        for(int i = 0;i < q; i++){            scanf("%d",&op);            if(op){                scanf("%d%d",&u,&v);                if(!vis[u]||!vis[v]){                    printf("ERROR! At path %d to %d\n",u,v);                }                else{                    if(dis[u][v] == inf) printf("No such path\n");                    else{                        printf("%d\n",dis[u][v]);                    }                }            }            else{                scanf("%d",&u);                if(vis[u]){                    printf("ERROR! At point %d\n",u);                }                else{                    mark[nn] = u;//标记激活的点                    vis[u] = 1;                    //下面就是模拟每添加一个点多出来的计算                    for(int i = 0;i < nn; i++)                        for(int j = 0;j < nn; j++) dis[mark[j]][u] = min(dis[mark[j]][u],dis[mark[j]][mark[i]] + dis[mark[i]][u]);                    for(int i = 0;i < nn; i++)                        for(int j = 0;j <= nn; j++) dis[u][mark[j]] = min(dis[u][mark[j]],dis[u][mark[i]] + dis[mark[i]][mark[j]]);                    for(int i = 0;i <= nn; i++)                        for(int j = 0;j <= nn; j++) dis[mark[i]][mark[j]] = min(dis[mark[i]][mark[j]],dis[mark[i]][u] + dis[u][mark[j]]);                    nn++;                }            }        }    }    return 0;}
看了别人的题解以后,题解里提到严蔚敏老师的数据结构那本书,书的190页对floyd作了比较详细的原理解释。大致意思就是说,最外层循环枚举每一个可能通过的点,当枚举到k这个点的时候,dis[i][j]实际上就是从i到j中间经过序号不大于k的最短路径。而在内层两个循环中已经完成了i~k和k~j的最短路寻找。所以经过比较得到的就是最短路径。

总的来说,这道题的题意就是对floyd的原理的解读。

依照原理又写了一发。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;#define inf 0x3f3f3f3fint dis[305][305];bool vis[305];int n,m,q;void floyd(int x){     for(int i = 0;i < n; i++) for(int j = 0; j < n; j++) dis[i][j] = min(dis[i][j],dis[i][x] + dis[x][j]);}int main(){    int u,v,len,op,cas = 1;    while(~scanf("%d%d%d",&n,&m,&q)){        if(n==0&&m==0&&q==0) break;        if(cas > 1) printf("\n");        printf("Case %d:\n",cas++);        memset(dis,0x3f,sizeof(dis));        memset(vis,0,sizeof(vis));        for(int i = 0;i < n; i++) dis[i][i] = 0;        for(int i = 0;i < m; i++){            scanf("%d%d%d",&u,&v,&len);            dis[u][v] = min(len,dis[u][v]);        }        for(int i = 0;i < q; i++){            scanf("%d",&op);            if(op){                scanf("%d%d",&u,&v);                if(!vis[u]||!vis[v]){                    printf("ERROR! At path %d to %d\n",u,v);                }                else{                    if(dis[u][v] == inf) printf("No such path\n");                    else{                        printf("%d\n",dis[u][v]);                    }                }            }            else{                scanf("%d",&u);                if(vis[u]){                    printf("ERROR! At point %d\n",u);                }                else{                    vis[u] = 1;                    floyd(u);                }            }        }    }    return 0;}


其实这应该是第四次学习floyd了,集训的时候学过一次,离散学过warshell,数据结构书里也有floyd,反而是这一次才真正领悟...

感悟:1.要多看书..2.学习不能功利...一知半解要不得

ps.这题交G++跑了C++两倍的时间,是什么神奇的原因呢...?

0 0
原创粉丝点击