//单源最短路之Dijkstra算法
/*朴素的dijkstra算法,复杂度为O(V²);*/
const int INF = INT_MAX;
int d[N],vis[N];
int w[N][N];
void dijkstra(int s, int n)
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++) d[i] = (i==s ? 0 : INF);
for(int i=1; i<=n; i++) {
int x,m = INF;
for(int j=1; j<=n; j++)
if(!vis[j] && d[j]<m)
m = d[x=j];
vis[x] = 1;
for(int j=1; j<=n; j++)
if(d[j] < d[x]+w[x][j])
d[j] = d[x] + w[x][j];
}
}
/*使用优先队列的Dijkstra算法,复杂度为O(ElogV),
因此它适用于E远小于V²的稀疏图。 */
const int INF = INT_MAX;
struct Edge {
int from, to, w;
Edge(){}
Edge(int a, int b, int c):from(a),to(b),w(c){}
};
vector<Edge>edges;
vector<int>G[N];
void AddEdge(int from, int to, int w)
{
edges.push_back(Edge(from,to,w));
edges.push_back(Edge(to,from,w));
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
int vis[N],d[N],w[N][N];
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> >q;
void dijkstra(int s, int n)
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++) d[i] = (i==s ? 0 : INF);
while(!q.empty()) q.pop();
q.push(make_pair(d[s],s));
while(!q.empty()) {
pii u = q.top(); q.pop();
int x = u.second;
if(vis[x]) continue;
vis[x] = 1;
for(int i=0; i<G[x].size(); i++) {
Edge &e = edges[G[x][i]];
if(d[e.to] > d[x] + e.w)
d[e.to] = d[x] + e.w,
q.push(make_pair(d[e.to],e.to));
}
}
}
-------------------------------------------------------
//单源最短路之Bellman-Ford 算法
/**
对于带负权边的图,Dijkstra算法便无能为力了,
而Bellman-Ford算法可以解决这个问题
*/
/*朴素的Bellman-Ford算法,复杂度为O(VE).*/
int u[M],v[M],w[M];
int d[N];
bool BF(int s, int n, int m) //s:源点 n:点个数 m:边个数
{
for(int i=1; i<=n; i++) d[i] = (i==s ? 0 : INF);
for(int k=1; k<n; k++) { //n-1次松弛
for(int i=1; i<=m; i++) //检查每条边
{
int x = u[i], y = v[i];
if(d[x] < INF) d[y] = min(d[y],d[x]+w[i]);
}
}
for(int k=1; k<=n; k++) { //判负环
for(int i=1; i<=m; i++)
{
int x = u[i], y = v[i];
if(d[x] < INF && d[y] > d[x] + w[i])
return false;
}
}
return true;
}
/*实践中,常用FIFO队列来代替上面的循环检查*/
int inq[N],d[N];
int sum[N]; //记录点出入队列的次数
vector<Edge>edges;
vector<int>G[N];
bool BF(int s, int n)
{
queue<int>q;
for(int i=1; i<=n; i++) d[i] = (i==s ? 0 : INF);
memset(inq,0,sizeof(inq));
memset(sum,0,sizeof(sum));
sum[s] = 1;
q.push(s);
while(!q.empty()) {
int x = q.front(); q.pop();
inq[x] = 0;
for(int i=0; i<G[x].size(); i++) {
Edge &e = edges[G[x][i]];
if(d[e.to] > d[x] + e.w) {
d[e.to] = d[x] + e.w;
if(!inq[e.to]) {
if(++sum[e.to] == n) return false;
inq[e.to] = 1;
q.push(e.to);
}
}
}
}
return true;
}
-------------------------------------------------------
//Floyd算法
/*如果要求出任意两点之间的最短路,不必调用n次dijkstra或
Bellman-Ford,更简单的Floyed算法非常适合,无论边权正负,
复杂度O(V³); */
int d[N][N];
void Floyed(int n)
{
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(d[[i][k]!=INF && d[k][j]<INF)
d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
}
/*Floyed求最小环*/
/*Floyed算法是按照点的编号增加的顺序更新最短路的,
假设环的最大号点是u,相邻两点为i,j,则在用u点更新
d[i][j]前,d[i][j] = w[i][u] + w[u][j],一定是一个
环 */
int d[N][N],w[N][N];
void MinCircle(int n)
{
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++) //最小环判定
for(int j=1; j<=n; j++)
if(d[i][j]!=INF && w[i][k]!=INF && w[k][j]!=INF
&& d[i][j] + w[i][k] + w[k][j] < mincircle)
mincircle = d[i][j] + w[i][k] + w[k][j];
for(int i=1; i<=n; i++) //Floyed部分
for(int j=1; j<=n; j++)
if(d[i][k]!=INF && d[k][j]!=INF)
d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
}
}
最短路算法总结
最新推荐文章于 2021-02-19 16:40:35 发布