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;
}