最短路模版整理
2014-08-20 19:03
357 查看
接着前一篇,整理完最小生成树的模版,接下来整理一下最短路的模版。
所有题目都是根据HDU 1874 写的。
图论中求最短路的算法比较多,有Dijkstra、Bellman-ford、Floyd-Warshall、以及SPFA。主要用到的就是这么几个算法。下面一一介绍。
一、Dijkstra
这个算法的做法就是,每次找到一个距源点距离最近的点,然后扩展这个与这个点相邻的点的距离。 这个算法只能针对非负权图进行求单源最短路,算法复杂度是O(V^2)(不优化),但是可以通过堆优化(我就用优先队列写写吧。。)复杂度可以降到O(V+ElogV)
未优化模版:
对于找最小值的过程,可以用堆优化,为了方便,用优先队列实现。
模版如下
二、Bellman-Ford
这个算法思想特别神奇。将起点的距离设为0,其他点设为INF,对于每一条边都做一次松弛操作。总共进行n-1次这样的操作。这样之后,dis数组里存的就是s到各点的最短距离。其实每次操作都只是更新了前一次更新的点,所以进行了很多不必要的扫描。SPFA正是把这些不必要的操作去掉得到的优化。
Bellman-Ford(普通做法 复杂度O(VE))
SPFA(好用,好写,复杂度小)
三、Floyd-Warshall
这个算法非常好写,原理基于动态规划,就不细说了。。能求出任意两点间的最短路,必须使用邻接矩阵存图,复杂度是O(n^3)
模版
算法很多,但是要把这些算法都学以致用很不容易。大概以后每道题都要想想多解,才能把这些图论算法的适用范围和自己的优势给弄清楚吧。还差了很多火候。
所有题目都是根据HDU 1874 写的。
图论中求最短路的算法比较多,有Dijkstra、Bellman-ford、Floyd-Warshall、以及SPFA。主要用到的就是这么几个算法。下面一一介绍。
一、Dijkstra
这个算法的做法就是,每次找到一个距源点距离最近的点,然后扩展这个与这个点相邻的点的距离。 这个算法只能针对非负权图进行求单源最短路,算法复杂度是O(V^2)(不优化),但是可以通过堆优化(我就用优先队列写写吧。。)复杂度可以降到O(V+ElogV)
未优化模版:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; struct edge{ int u,v,next,w; }e[1005]; int head[205],cnt; int d[205],vis[205]; int n,m; void addedge(int u,int v,int w){ e[cnt].u = u; e[cnt].v = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt++; } int Dijkstra(int s,int t){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); d[s] = 0; for(int i=0;i<n;i++){ int k = -1,minn = INF; for(int j=0;j<n;j++) if(!vis[j]&&d[j]<minn) minn = d[j],k = j; if(k == -1)break; vis[k] = 1; for(int j = head[k];j!=-1;j = e[j].next){ int v = e[j].v,w = e[j].w; if(!vis[v]&& d[v]>d[k]+w) d[v] = d[k]+w; } } if(d[t] == INF)return -1; return d[t]; } int main() { while(scanf("%d%d",&n,&m)==2){ int u,v,w; memset(head,-1,sizeof(head)); cnt = 0; while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } scanf("%d%d",&u,&v); printf("%d\n",Dijkstra(u,v)); } return 0; }
对于找最小值的过程,可以用堆优化,为了方便,用优先队列实现。
模版如下
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; typedef pair<int ,int > PII; struct edge{ int u,v,next,w; }e[1005]; int head[205],cnt; int d[205],vis[205]; int n,m; void addedge(int u,int v,int w){ e[cnt].u = u; e[cnt].v = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt++; } int Dijkstra(int s,int t){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); d[s] = 0; priority_queue <PII,vector<PII>,greater<PII> >q; q.push(make_pair(d[s],s)); while(!q.empty()){ PII t = q.top(); q.pop(); vis[t.second] = 1; int k = t.second; for(int j = head[k];j!=-1;j = e[j].next){ int v = e[j].v,w = e[j].w; if(!vis[v]&&d[v]>d[k]+w) d[v] = d[k]+w,q.push(make_pair(d[v],v)); } } if(d[t] == INF)return -1; return d[t]; } int main() { while(scanf("%d%d",&n,&m)==2){ int u,v,w; memset(head,-1,sizeof(head)); cnt = 0; while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } scanf("%d%d",&u,&v); printf("%d\n",Dijkstra(u,v)); } return 0; }
二、Bellman-Ford
这个算法思想特别神奇。将起点的距离设为0,其他点设为INF,对于每一条边都做一次松弛操作。总共进行n-1次这样的操作。这样之后,dis数组里存的就是s到各点的最短距离。其实每次操作都只是更新了前一次更新的点,所以进行了很多不必要的扫描。SPFA正是把这些不必要的操作去掉得到的优化。
Bellman-Ford(普通做法 复杂度O(VE))
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; struct edge{ int u,v,w; }e[1005]; int n,m,cnt; int d[205]; int Bellman_ford(int s){ memset(d,0x3f,sizeof(d)); d[s] = 0; for(int i=1;i<n;i++) for(int j=1;j<=cnt;j++) d[e[j].v] = min(d[e[j].v],d[e[j].u]+e[j].w); for(int i=1;i<=cnt;i++) if(d[e[i].v]>d[e[i].u]+e[i].w)return 0; return 1; } int main() { while(scanf("%d%d",&n,&m)==2){ int u,v,w,st,ed; cnt = 0; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w),e[++cnt].u = u,e[cnt].v = v,e[cnt].w = w; e[++cnt].u = v,e[cnt].v = u,e[cnt].w = w; } scanf("%d%d",&st,&ed); int ok = Bellman_ford(st); if(ok && d[ed]!=INF)printf("%d\n",d[ed]); else puts("-1"); } return 0; }
SPFA(好用,好写,复杂度小)
#include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; struct edge{ int u,v,w,next; }e[1005]; int head[205],d[205],inq[205],cnt,n,m; void addedge(int u,int v,int w){ e[cnt].u = u; e[cnt].v = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt++; } int SPFA(int s){ memset(inq,0,sizeof(inq)); memset(d,0x3f,sizeof(d)); d[s] = 0; queue<int>q; q.push(s); while(!q.empty()){ int t = q.front(); q.pop(); inq[t] = 0; for(int i=head[t];i!=-1;i = e[i].next){ int v = e[i].v,w = e[i].w; if(d[v]>d[t]+w){ d[v] = d[t]+w; if(!inq[v])inq[v] = 1,q.push(v); } } } for(int i=0;i<cnt;i++) if(d[e[i].v]>d[e[i].u]+e[i].w)return 0; return 1; } int main() { while(scanf("%d%d",&n,&m)==2){ int u,v,w,st,ed; cnt = 0; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w),addedge(v,u,w); } scanf("%d%d",&st,&ed); int ok = SPFA(st); if(ok&&d[ed]!=INF)printf("%d\n",d[ed]); else puts("-1"); } return 0; }
三、Floyd-Warshall
这个算法非常好写,原理基于动态规划,就不细说了。。能求出任意两点间的最短路,必须使用邻接矩阵存图,复杂度是O(n^3)
模版
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; int g[205][205]; int n,m; int main() { while(scanf("%d%d",&n,&m)==2){ int u,v,w; memset(g,0x3f,sizeof(g)); for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w);g[u][v] = g[v][u] = min(g[u][v],w);} int st,ed; scanf("%d%d",&st,&ed); for(int i=0;i<n;i++)g[i][i] = 0; for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(g[i][j]>g[i][k]+g[k][j]) g[i][j] = g[i][k]+g[k][j]; if(g[st][ed] == INF)g[st][ed] = -1; printf("%d\n",g[st][ed]); } return 0; }
算法很多,但是要把这些算法都学以致用很不容易。大概以后每道题都要想想多解,才能把这些图论算法的适用范围和自己的优势给弄清楚吧。还差了很多火候。
相关文章推荐
- 最短路题目整理 Hdu 2066 + 1839 + LightOJ 1099(次短路)
- 整理的一些模版LCS(连续和非连续)
- 最短路,最小生成树,及拓扑排序模板整理
- 最短路模版(dijkstra)
- HDU_2544——最短路,Dijkstra模版
- 最小生成树的两种算法及模版整理
- 单源最短路模版
- 考前模版整理
- POJ 2449 第K短路模版题 A*+最短路
- 整理《挑战程序设计竞赛》中最短路的代码
- python模块整理13-json模版
- Floyd,Dijkstra,SPFA模板整理(以[HDU2544-最短路]为例 )
- 模版整理(数据结构)【待更新】
- 最短路最长路整理
- 最短路,模版
- 全源最短路模版
- dedecsm系统(企业简介)类单栏目模版如何修改和调用整理
- 最短路模版
- 设计模式之模版方法模式_动力节点Java学院整理
- poj 3463 (次短路的模版)