HDU 3631 Shortest Path (Floyd的深层理解)
2015-03-08 22:31
417 查看
题目链接:点击打开链接
题目大意:有一张有向图,300个点,然后有10^5次操作,操作有两种,一种是激活某一个点,另一种是询问两个点之间的最短路径,这条路径必须由被激活的点构成。
显然任意两点之间的距离理想的是floyd。
这题让我对floyd有了更深的理解,以前一直觉得floyd非常好写,但是对于其原理一知半解,在这个变形应用里就遇到了困难。
我最开始非常原始的想法就是,如果floyd里加入一个点,多出来的运算如何表述。写了一发,只是找规律,没有理解其精髓。
总的来说,这道题的题意就是对floyd的原理的解读。
依照原理又写了一发。
其实这应该是第四次学习floyd了,集训的时候学过一次,离散学过warshell,数据结构书里也有floyd,反而是这一次才真正领悟...
感悟:1.要多看书..2.学习不能功利...一知半解要不得
ps.这题交G++跑了C++两倍的时间,是什么神奇的原因呢...?
题目大意:有一张有向图,300个点,然后有10^5次操作,操作有两种,一种是激活某一个点,另一种是询问两个点之间的最短路径,这条路径必须由被激活的点构成。
显然任意两点之间的距离理想的是floyd。
这题让我对floyd有了更深的理解,以前一直觉得floyd非常好写,但是对于其原理一知半解,在这个变形应用里就遇到了困难。
我最开始非常原始的想法就是,如果floyd里加入一个点,多出来的运算如何表述。写了一发,只是找规律,没有理解其精髓。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; #define inf 0x3f3f3f3f int 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 0x3f3f3f3f int 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++两倍的时间,是什么神奇的原因呢...?
相关文章推荐
- HDU 3631 Shortest Path 【floyd的深层理解】
- hdu 3631 Shortest Path(Floyd)
- HDU - 3631 Shortest Path(Floyd最短路)
- hdu 3631 Shortest Path (floyd)
- hdu 3631 Shortest Path (floyd)
- HDU 3631 Shortest Path(Floyd变形)
- hdu 3631 Shortest Path (floyd)
- hdu 3631 Shortest Path(Floyd)
- hdu 3631 Shortest Path(Floyd)
- hdu 3631 Shortest Path(Floyd)
- Hdu 3631 Shortest Path(Floyd插点)
- hdu 3631 Shortest Path(floyd)
- HDU-3631 Shortest Path (floyd)
- hdu 3631 Shortest Path【Floyd】
- HDU 3631(Shortest Path) 最短路问题 (Floyd)
- 【HDU】3631 Shortest Path 【floyd】
- hdu 3631(floyd思想的运用)
- hdu 4034 Graph (floyd的深入理解)
- HDU 3631 Shortest Path
- hdu 3631 floyd最短路