Dijkstra(迪杰斯特拉)算法
解决无负权边的带权有向图或无向图的单源最短路问题
用邻接表,不优化,时间复杂度O(V2+E)
Dijkstra+堆的时间复杂度 o(ElgV)
用斐波那契堆可以做到O(VlogV+E)
若要输出路径,则设置prev数组记录每个节点的前趋点,在d[i] 更新时更新prev[i]
#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
const int inf=0x3f3f3f3f;
struct node{
int to,val;
node(){}
node(int a,int b){to=a;val=b;}
bool operator<(const node &xx)const{
return xx.val<val;
}
};
vector<node> mp[N];
int n,m;
int dis[N];
void dijkstra(int s)
{
memset(dis,inf,sizeof dis);
priority_queue<node> q;
q.push(node(s,0));dis[s]=0;
while(!q.empty())
{
int from=q.top().to; q.pop();
for(int i=0;i<mp[from].size();i++)
{
int to=mp[from][i].to;
int val=mp[from][i].val;
if(dis[to]>dis[from]+val)
q.push(node(to,dis[to]=dis[from]+val));
}
}
printf("%d\n",dis[n]);
}
int main()
{
int i,j,t,tt=0;
while(~scanf("%d%d",&n,&m),n|m)
{
memset(mp,0,sizeof mp);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(node(b,c));
mp[b].push_back(node(a,c));
}
dijkstra(1);
}
}
经典例题:poj 3159
解决含负权边的带权有向图的单源最短路径问题
不能处理带负权边的无向图(因可以来回走一条负权边)
限制条件: 要求图中不能包含权值总和为负值回路(负权值回路
假设图的顶点个数为n,边的个数为e
使用邻接表存储图,复杂度O(n*e)
使用邻接矩阵存储图,复杂度为O(n3);
Bellman-Ford算法不一定要循环n-1次,n为顶点个数
只要在某次循环过程中,考虑每条边后,源点到所有顶点的最短路径 长度都没有变,那么Bellman-Ford算法就可以提前结束了
第n次可以判断是否有负权值回路
(本题是把边扩展成2*e个,变成”有向图”求解)
#include <cstdio>
const int max_v = 110;
const int max_e = 10010;
const int INF = 1000000000;
int e,v;
struct edge {
int from,to,cost;
};
int d[max_v];
edge eg[max_e*2];
int main()
{
while(scanf("%d%d",&v,&e) && v) {
//边扩展到1-2e范围
for(int i = 0 ; i < max_v ; i ++) d[i] = INF;
for(int i = 1 ; i <= e ; i ++) {
scanf("%d%d%d",&eg[i].from,&eg[i].to,&eg[i].cost);
eg[i+e].from = eg[i].to;
eg[i+e].to = eg[i].from;
eg[i+e].cost = eg[i].cost;
}
d[1] = 0;
while(true) {
bool flag = false;
for(int i = 1 ; i <= 2*e ; i ++) {
if(d[eg[i].from] != INF && d[eg[i].from]+eg[i].cost < d[eg[i].to]) {
d[eg[i].to] = d[eg[i].from]+eg[i].cost;
flag = true;
}
}
if(!flag) break;
}
printf("%d\n",d[v]);
}
return 0;
}
经典例题:poj 1860 3259 2240
SPFA(队列优化))算法快速求解含负权边的带权有向图的单源最短路径问题
是Bellman-Ford算法的改进版,利用队列动态更新dist[]
在平均情况下,SPFA算法的期望时间复杂度为O(E)
#include<bits/stdc++.h>
#include<stdlib.h>
#include<stdio.h>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e3;
const int inf=0x3f3f3f3f;
struct node{
int to,val;
node(){}
node(int a,int b){to=a;val=b;}
};
vector<node> mp[N];
int n,m;
int dis[N];
bool used[N];
bool spfa(int s)
{
memset(dis,inf,sizeof dis);
memset(used,0,sizeof used);
queue<int> q;
q.push(s);dis[s]=0;used[s]=1;
while(!q.empty())
{
int from=q.front();q.pop();
used[from]=0;
for(int i=0;i<mp[from].size();i++)
{
int to=mp[from][i].to;
int val=mp[from][i].val;
if(dis[to]>dis[from]+val)
{
dis[to]=dis[from]+val;
if(!used[to])
used[to]=1,q.push(to);
}
}
}
return 0;
}
int main()
{
int i,j,t,tt=0;
while(~scanf("%d%d",&n,&m),n|m)
{
memset(mp,0,sizeof mp);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(node(b,c));
mp[b].push_back(node(a,c));
}
spfa(1);
printf("%d\n",dis[n]);
}
}
经典例题:poj 2387 3256
http://poj.org/problem?id=3259
//#include<bits/stdc++.h>
#include<stdlib.h>
#include<stdio.h>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N=500+7;
const int inf=0x3f3f3f3f;
int mp[N][N];
int n,m,k;
int dis[N];
bool used[N];
int in[N];
bool spfa(int s)
{
memset(dis,inf,sizeof dis);
memset(used,0,sizeof used);
memset(in,0,sizeof in);
queue<int> q;
q.push(s);
dis[s]=0;used[s]=1;in[s]=1;
while(!q.empty())
{
int from=q.front();q.pop();
used[from]=0;
for(int i=1;i<=n;i++)
{
int to=i;
int val=mp[from][i];
if(dis[to]>dis[from]+val)
{
dis[to]=dis[from]+val;
if(!used[to])
{
in[to]++;
if(in[to]==n) return 1;//存在一点入队次数大于总顶点数
used[to]=1,q.push(to);
}
}
}
if(dis[s]<0) return 1;//优化
}
return 0;
}
int main()
{
int i,j,t,tt=0;
scanf("%d",&t);
while(t--)
{
memset(mp,inf,sizeof mp);
scanf("%d%d%d",&n,&m,&k);
int a,b,c;
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a][b]=mp[b][a]=min(mp[a][b],c);
}
while(k--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a][b]=min(mp[a][b],-c);
}
if(spfa(1)) printf("YES\n");
else printf("NO\n");
}
}
Floyd(弗洛伊德)算法
用于求每一对顶点之间的最短路径。有向图,无向图均可,也可以有负权边
时间复杂度O(n3)
空间复杂度O(n2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e2+7;
const int inf=0x7fffffff;
int f[N][N];
int main()
{
int i,j,k,m,n,t,tt=0;
while(scanf("%d%d",&n,&m),n|m)
{
int a,b,c;
memset(f,0x3f3f3f3f,sizeof(f));
for(i=0;i<m;i++) cin>>a>>b>>c,f[a][b]=c,f[b][a]=c;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
cout<<f[1][n]<<endl;
}
return 0;
}
经典例题:poj 1125
http://lx.lanqiao.cn/problem.page?gpid=T22解题报告:http://blog.csdn.net/yyii1111/article/details/18905125
spfa
#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
bool vis[N];
void spfa(int s)
{
memset(dis,inf,sizeof dis);dis[s]=0;
memset(vis,0,sizeof vis); vis[s]=1;
queue<int> q; q.push(s);
while(!q.empty())
{
s=q.front();q.pop();
vis[s]=0;
for(int i=0;i<mp[s].size();i++)
{
int e=mp[s][i].first;
int val=mp[s][i].second;
if(dis[e]>dis[s]+val)
{
dis[e]=dis[s]+val;
if(!vis[e]) vis[e]=1,q.push(e);
}
}
}
}
int main()
{
int i,j,t,tt=0,s,x,y,n,m;
int a,b,c;
while(~scanf("%d%d%d%d",&n,&x,&y,&s))
{
memset(mp,0,sizeof mp);
while(x--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
mp[b].push_back(make_pair(a,c));
}
while(y--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
}
spfa(s);
for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
else printf("NO PATH\n");
}
spfa优化
#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
bool vis[N];
void spfa(int s)
{
memset(dis,inf,sizeof dis);dis[s]=0;
memset(vis,0,sizeof vis); vis[s]=1;
deque<int> q; q.push_back(s);
while(!q.empty())
{
s=q.front();q.pop_front();
vis[s]=0;
for(int i=0;i<mp[s].size();i++)
{
int e=mp[s][i].first;
int val=mp[s][i].second;
if(dis[e]>dis[s]+val)
{
dis[e]=dis[s]+val;
if(!vis[e])
{
vis[e]=1;
if(!q.empty())
{
if(dis[e]>dis[q.front()])
q.push_back(e);
else q.push_front(e);
}
else q.push_back(e);
}
}
}
}
}
int main()
{
int i,j,t,tt=0,s,x,y,n,m;
int a,b,c;
while(~scanf("%d%d%d%d",&n,&x,&y,&s))
{
memset(mp,0,sizeof mp);
while(x--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
mp[b].push_back(make_pair(a,c));
}
while(y--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
}
spfa(s);
for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
else printf("NO PATH\n");
}
}
dijkstra
#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
struct node{
int to,val;
node(){}
node(int a,int b){to=a;val=b;}
bool operator<(const node &xx)const{
return xx.val<val;
}
};
vector<node> mp[N];
int dis[N];
void dijkstra(int s)
{
memset(dis,inf,sizeof dis);dis[s]=0;
priority_queue<node> q;q.push(node(s,0));
while(!q.empty())
{
s=q.top().to; q.pop();
for(int i=0;i<mp[s].size();i++)
{
int e=mp[s][i].to;
int val=mp[s][i].val;
if(dis[e]>dis[s]+val)
q.push(node(e,dis[e]=dis[s]+val));
}
}
}
int main()
{
int i,j,t,tt=0,s,x,y,n,m;
int a,b,c;
while(~scanf("%d%d%d%d",&n,&x,&y,&s))
{
memset(mp,0,sizeof mp);
while(x--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(node(b,c));
mp[b].push_back(node(a,c));
}
while(y--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(node(b,c));
}
dijkstra(s);
for(int i=1;i<=n;i++)
if(dis[i]!=inf) printf("%d\n",dis[i]);
else printf("NO PATH\n");
}
}
有问题
#include<bits/stdc++.h>
using namespace std;
const int N=25000+10;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pall;
vector<pall> mp[N];
int dis[N];
void dijkstra(int s)
{
memset(dis,inf,sizeof dis);dis[s]=0;
priority_queue<pall> q; q.push(make_pair(s,0));
while(!q.empty())
{
s=q.top().first; q.pop();
for(int i=0;i<mp[s].size();i++)
{
int e=mp[s][i].first;
int val=mp[s][i].second;
if(dis[e]>dis[s]+val)
q.push(make_pair(e,dis[e]=dis[s]+val));
}
}
}
int main()
{
int i,j,t,tt=0,s,x,y,n,m;
int a,b,c;
while(~scanf("%d%d%d%d",&n,&x,&y,&s))
{
memset(mp,0,sizeof mp);
while(x--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
mp[b].push_back(make_pair(a,c));
}
while(y--)
{
scanf("%d%d%d",&a,&b,&c);
mp[a].push_back(make_pair(b,c));
}
dijkstra(s);
for(int i=1;i<=n;i++) if(dis[i]!=inf) printf("%d\n",dis[i]);
else printf("NO PATH\n");
}