最短路算法总结



//单源最短路之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]);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值