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
- 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 5636:Shortest Path floyd
- HDU 5636:Shortest Path【Floyd】
- HDU 3631(Shortest Path) 最短路问题 (Floyd)
- hdu 3631 Shortest Path 最短路径+插点法+floyd
- Hdu 3631 Shortest Path(Floyd插点)
- 基于SVN + Maven的构建发布Demo之二——解决回滚问题
- 搜索引擎倒排索引表压缩:gamma编码
- Linux显示邮件状态等信息
- 递归四条基本法则
- #include <sys/types.h>的作用
- HDU 3631 Shortest Path (Floyd的深层理解)
- Linux程序设计(Linux shell编程八)
- android中 camera 拍照应用详解
- Android基础笔记(三)-数据存储和界面展现
- 1016. Phone Bills (25)
- HTTP 协议之压缩
- 没收心的人是需要别人适当地提醒的
- 东半球最好的SecureCRT高级教程
- HDU 1009 贪心水题