最短路算法汇总(Dijkstra,Bellman-Ford,SPFA以及Floyd)

 

1)Dijkstra 算法 --- 求单源最短路径(边的权值非负),所谓 单源最短路径

(single source shortest path)就是固定一个顶点为源点,求源点到其他每个顶点的最短路径;

2)  Bellman-Ford 算法 --- 求单源最短路径(边的权值允许为负值,但不存在负权值回路);

Dijkstra算法:顶点的dist值一经确定就不会改变,而 Bellman-Ford中顶点的dist值可能会改变。

3)  SPFA 算法 --- Bellman-Ford 算法的改进  ;

4)  求(多源最短路)所有顶点之间的最短路径(边的权值允许为负值,但不存在负权值回路) ---- Floyd算法

以上 4 个算法均适用于无向图和有向图。

Dijkstra模板:

#include<cstdio>   //O(nlogn) 堆优化
#include<algorithm>   
#include<vector>   
#include<queue>
#include<cstring>   //含memset 
using namespace std;
#define PII pair<int,double>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
#define maxn 100005

int n,m,S,T;
vector<PII> edge[maxn];
int d[maxn];
bool vis[maxn];
class mycmp{
	public:
	bool operator ()(const PII& a,const PII& b)const{
		return a.se>b.se;
	}
};
priority_queue<PII,vector<PII>,mycmp> que;

int main(){
	scanf("%d%d%d%d",&n,&m,&S,&T); //顶点,边数,起点,终点.
	int u,v,w;
	for(int i=0;i<m;++i){
		scanf("%d%d%d",&u,&v,&w);
		edge[u].pb(mp(v,w));
		edge[v].pb(mp(u,w));
	}
	memset(d,0x3f,sizeof(d));
	d[S]=0;
	que.push(mp(S,d[S]));
	while(!que.empty()){
		PII tmp=que.top();que.pop();
		if(tmp.fi==T) break;
		vis[tmp.fi]=1;
		
for(int i=0;i<edge[tmp.fi].size();i++)
		{
			PII v=edge[tmp.fi][i];
			if(!vis[v.fi] && d[tmp.fi]+v.se<d[v.fi])
			{
				d[v.fi]=d[tmp.fi]+v.se;
				que.push( mp(v.fi,d[v.fi]) );
			}
		}
        /*  for(auto p:edge[tmp.fi]){
			if(!vis[p.fi]&&d[tmp.fi]+p.se<d[p.fi]){
				d[p.fi]=d[tmp.fi]+p.se;
				que.push(mp(p.fi,d[p.fi]));
			}
		}邻接表的另一种遍历方式*/
	}
	printf("%d\n",d[T]);
	return 0;
}
/*
input:
5 6 1 4
1 2 2
1 3 1
2 4 5
2 5 4
4 1 15
3 2 1
output:
7
*/

POJ1135:

#include<iostream>   //本题思路先用dijkstra把dist数组求出来,然后找出dist值最大的顶点end,从v0到end的距离作为max1 
#include<vector>     // 然后再把所有的边的 (dist[i]+dist[j]+edge[i][j])/2.0 取 max2
#include<queue>   
#include<cstring>     
#include<algorithm>
#include<map>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define maxn 0x3f3f3f3f
using namespace std;
const int N=10005;
int n,m; //顶点数边数
vector<pii> edge[N];
int dist[N];    
int vis[N];  
double max1=-1,max2=-1;
class mycmp{
	public:
	bool operator()(const pii &a,const pii &b )const{
	return a.se>b.se;
	}
	
};
priority_queue<pii,vector<pii> ,mycmp> que;

void dijkstra(int v0)
{
	que.push(mp(1,dist[1]));
	while(!que.empty())
	{
		pii tmp=que.top();
		que.pop();
		vis[tmp.fi]=1;
		for(int i=0;i<edge[tmp.fi].size();i++)  
		{
			int v=edge[tmp.fi][i].fi;
			if(!vis[v] && dist[tmp.fi]+edge[tmp.fi][i].se< dist[v] )
			{
				vis[v]=1;
				dist[v]=dist[tmp.fi]+edge[tmp.fi][i].se;
				que.push(mp(v,dist[v]));
			}
		}
	}
	//dist数组处理完成 
}
int main()
{
	cin>>n>>m;
	int u,v,w;
	for(int i=0;i<m;i++)
	{
		cin>>u>>v>>w;
		edge[u].pb(mp(v,w));
		edge[v].pb(mp(u,w));
	}
	memset(dist,maxn,sizeof(dist));
	dist[1]=0; //v0
	dijkstra(1);

	for(int i=1;i<=n;i++)
	{
		if(max1<dist[i])
		max1=dist[i];
	}
	//遍历邻接表 
	for( int i=1;i<=n;i++)
	{
		for(int j=0;j<edge[i].size();j++)
		{
			int x=edge[i][j].fi; //x是i的邻接点 
			double y=dist[i]+dist[x]+edge[i][j].se;
			y/=2.0;
			if(max2<y)
			{
				max2=y;
			}
		}
	} 
	
	cout<<max(max1,max2)<<endl;
	
	 //cout<<dist[2];
		
	
}
	/*
Sample Input
2 1
1 2 27

3 3
1 2 5
1 3 5
2 3 5

0 0
Sample Output
System #1
The last domino falls after 27.0 seconds, at key domino 2.

System #2
The last domino falls after 7.5 seconds, between key dominoes 2 and 3.

*/ 

 Bellman-Ford:

核心代码 
for(int k = 1 ; k <= n - 1 ; 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] ;
    }
}

SPFA模板:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first 
#define se second
#define pb push_back
#define mp make_pair
#define maxn 0x3f3f3f3f
using namespace std;
const int N=10005;
int dist[N];
int vis[N];
int path[N];
int n,m; //顶点数,边数
vector<pii> edge[N];
queue<int> Q;
void spfa()
{
	Q.push(0);
	int x;
	while(!Q.empty())
	{
		x=Q.front();
		vis[x]=0;
		Q.pop();
		for(int i=0;i<edge[x].size();i++)
		{
			pii v=edge[x][i];
			if(dist[x]+v.se<dist[v.fi] )
			{
				dist[v.fi]=dist[x]+v.se;
				path[v.fi]=x;
				vis[v.fi]=1;
				Q.push(v.fi);
				
			}
		} 
	}
} 
int main()
{
	int u,v,w;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		cin>>u>>v>>w;
		edge[u].pb(mp(v,w)); //有向图 
	}
	for(int i=0;i<n;i++)
	{
		dist[i]=maxn;
	}
	dist[0]=0;
	spfa();
	
	int tmp=6;
	cout<<tmp;
	while(path[tmp]!=0)
	{
		cout<<"->"<<path[tmp];
		tmp=path[tmp];
	} 
	cout<<"->0"<<endl;
	
	return 0;
}
/*
7 10
0 1 6
0 2 5
0 3 5
1 4 -1
2 1 -2
2 4 1
3 2 -2
3 5 -1
4 6 3
5 6 3

6->4->1->2->3->0

*/

floyd算法:

//Floyd-Warshall算法核心语句

for(k=1;k<=n;k++)

  for(i=1;i<=n;i++)

      for(j=1;j<=n;j++)

        if(e[i][k]<inf && e[k][j]<inf && e[i][j]>e[i][k]+e[k][j])

          {  e[i][j]=e[i][k]+e[k][j];
             path[i][j]=k;
          } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值