单源最短路径
2017-09-08 14:48
78 查看
单源最短路径的种种…
DP的算法
单源最短路径的种种DP的算法
NO1 only 5 lines Floyd算法
优缺点
基本概念
代码
NO2 Dijksra 算法
优缺点
基本概念
代码 On2
代码 复杂度On logn
NO3 Bellman-Ford 算法
声明
优缺点
基本思路
算法的过程
OR 队列优化的Bellaman
NO.1: only 5 lines – Floyd算法
优缺点:
*优点:1.可以处理负权值的图
2.算法简单!
缺点:
1.无法处理负权环的情况!
2. 三重循环,无法算大的数据.*
基本概念:
就是将每次设置一个k点作为中转站,在用1~n的i与j二重循环来套进去,利用一个矩阵来储存,如a[i][j]表示i->j的权值. 对每一个点进行松弛,看是否成功!转移方程:
if(a[i][k]<inf&&a[k][j]<inf&&a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];
代码:
#include<stdio.h>
#include <iostream>
using namespace std;
int main() {
int a[100][100],n,m,t1,t2,value;
int inf=999999;
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=inf;
cin>>m;
for(int i=1; i<=m; i++) {
cin>>t1>>t2>>value;
a[t1][t2]=value;
}
// Floyd-warshall 算法核心
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(a[i][k]<inf&&a[k][j]<inf&&a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++)
if(a[i][j]==inf) cout<<"∞";
else printf("%3d",a[i][j]);
cout<<endl;
}
}
NO.2: Dijksra 算法
优缺点:
优点:1.没有三重循环!
2.复杂度小
3.基于贪心策略!
缺点:1.无法处理负权值(因为会破坏确定值不变的情况)
基本概念:
就是每次找一个离一号点最近而且没有处理过的数字(book[ ]来储存是否操作)来将其作为”中转站”来松弛其他的点!用一个dis[ ]数组来储存值!
找最小点的代码:
min=inf; for(j=1;j<=n;j++) { if(book[j]==0 && dis[j]<min) { min=dis[j]; u=j; } }
代码 –O(n^2):
#include <stdio.h> int main() { int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min; int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值 //读入n和m,n表示顶点个数,m表示边的条数 scanf("%d %d",&n,&m); //初始化 for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i==j) e[i][j]=0; else e[i][j]=inf; //读入边 for(i=1;i<=m;i++) { scanf("%d %d %d",&t1,&t2,&t3); e[t1][t2]=t3; } //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程 for(i=1;i<=n;i++) dis[i]=e[1][i]; //book数组初始化 for(i=1;i<=n;i++) book[i]=0; book[1]=1; //Dijkstra算法核心语句 for(i=1;i<=n-1;i++) //每次循环定位一个数 { //找到离1号顶点最近的顶点 min=inf; for(j=1;j<=n;j++) { if(book[j]==0 && dis[j]<min) { min=dis[j]; u=j; } } book[u]=1; for(v=1;v<=n;v++) { if(e[u][v]<inf) { if(dis[v]>dis[u]+e[u][v]) dis[v]=dis[u]+e[u][v]; } } } //输出最终的结果 for(i=1;i<=n;i++) printf("%d ",dis[i]); getchar(); getchar(); return 0; }
代码 –复杂度O(n logn)
#include <iostream> #include <stdio.h> #include <algorithm> e9f6 ; #include <queue> #include <vector> using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int N=1000005; const int inf=999999; struct edge { int to,cost; bool road; edge(bool road,ll to=0,ll cost=0):road(road),to(to),cost(cost) {} }; int n,m,k; vector<edge> G ; ll d ; void dijstra(long long s) { //С¸ù¶ÑµÄ×ö·¨! priority_queue<P,vector<P>,greater<P> > que; fill(d,d+n,inf); d[1]=0; que.push(P(0,1)); while(!que.empty()) { P p=que.top(); que.pop(); int v=p.second; if(d[v]<p.first) continue; for(int i=0; i<G[v].size(); i++) { edge e=G[v][i]; if(d[e.to]>d[v]+e.cost) d[e.to]=d[v]+e.cost; que.push(P(d[e.to],e.to)); } } } int main() { //...... return 0; }
NO.3: Bellman-Ford 算法
声明:
如有雷同,纯属巧合,请勿介意!优缺点:
优点:1.可以判断负权回路
2.好像可以处理环哦!
3.简易易学(啊哈!)
缺点:
1.我觉得挺好的!
基本思路:
将原来1->i的点局设置为∞,在之后的m-1轮之中可以将其松弛,就是看
k==1->1点通过1条边能够到达的最小
k==2->1点通过2条边能够达到的最小
……
k==n->1点…..n…最小
即:
for(int k=1; k<=n-1; k++) //n-1条边的分别确定 即k->k条边 for(int i=1; i<=m; i++) if(dis[v[i]]>dis[u[i]]+w[i]) dis[v[i]]=dis[u[i]]+w[i];
所以说就是每次循环找出所有输入边的情况,在进行操作k-1轮!
算法的过程:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int n,m,dis[1000],u[1000],v[1000],w[1000];
int inf=999999;
cin>>n>>m;
for(int i=1; i<=m; i++)
cin>>u[i]>>v[i]>>w[i];
for(int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;
//Bellman-Ford 算法的核心;
for(int k=1; k<=n-1; k++) //n-1条边的分别确定 即k->k条边 for(int i=1; i<=m; i++) if(dis[v[i]]>dis[u[i]]+w[i]) dis[v[i]]=dis[u[i]]+w[i];
for(int i=1; i<=n; i++)
cout<<dis[i]<<" ";
}
/*
测试数据附赠:
Input:
5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
Output:
0 -3 -1 2 4
*/
OR 队列优化的Bellaman
#include <stdio.h> #include <iostream> using namespace std; int main() { int n,m; int u[10],v[10],w[10]; int first[10],next[10]; int dis[6]= {0},book[6]= {0}; int que[101]= {0},head=1,tail=1; int inf=9999999; cin>>n>>m; for(int i=1; i<=n; i++) dis[i]=inf; dis[1]=0; //³õʼ»¯bookÊý×é,Ò»¿ªÊ¼Îª0,±íʾ¾ù²»ÔÚ¶ÓÁÐÖÐ for(int i=1; i<=n; i++) book[i]=0; //½«ÁÚ½Ó±í³õʼ»¯Îª-1 ,±íʾÔÝʱ¶¼Ã»Óб߼ÓÈë for(int i=1; i<=n; i++) first[i]=-1; for(int i=1; i<=m; i++) { //¶ÁÈëÿһÌõ±ß cin>>u[i]>>v[i]>>w[i]; next[i]=first[u[i]]; first[u[i]]=i; } //1ºÅµãÈë¶Ó que[tail]=1; tail++; book[1]=1;//±íʾÈë¶Ó int k; while(head<tail) { k=first[que[head]];//¶ÓÊ×µÄÊý¾Ý while(k!=-1) { if(dis[v[k]]>dis[u[k]]+w[k]) dis[v[k]]=dis[u[k]]+w[k]; //ÓÃÒ»¸öbookÊý×éÅжÏÊÇ·ñÔÚ¶ÓÁÐÀï if(book[v[k]]==0) //Èç¹û²»Ê¹ÓÃbookÀ´¼Ç¼¾ÍҪÿ´Î´Óhead~tailɨһ±é! { que[tail]=v[k]; tail++; book[v[k]]=1;//±íʾv[k]ÒѾÈëÁÐ } k=next[k]; } //³ö¶Ó book[que[head]]=0; head++; } for(int i=1; i<=n; i++) printf("%d ",dis[i]); return 0; }
注:如有兴趣,请加关注哦!
相关文章推荐
- 算法导论笔记:24单源最短路径
- Dijkstra算法(单源最短路径)
- HDOJ1874 ( 畅通工程续 ) 【单源最短路径】
- Dijkstra单源最短路径,适合稠密图,顶点少,边多(c语言)
- 邻接表实现 单源最短路径SPFA算法
- 算法导论24(单源最短路径)
- HDU 2680 Choose the best route(单源最短路径)
- 单源最短路径问题(Bellman-Ford算法)
- 单源最短路径---Dijkstra 算法--路径还原
- 有向无环图的单源最短路径
- 贪心算法-单源最短路径
- 洛谷 3371_单源最短路径_spfa
- 单源最短路径
- Dijkstra算法(单源最短路径)
- 第十三章 ALDS1_12_B:Single Source Shortest Path I 单源最短路径
- hdoj 1535 Invitation Cards 【最短路径SPFA】【正反向建边求单源最短路之和】
- Dijkstra单源最短路径(贪心选择)
- Bellman-Ford算法:计算单源最短路径
- 图论算法(二)-最短路径的Dijkstra [ 单源 ] 和Floyd[ 多源 ] 解法(JAVA )
- (洛谷 3371)【模(mú)板】单源最短路径