最短路算法总结 dijkstra,bellman_ford,spfa poj 1125

http://acm.pku.edu.cn/JudgeOnline/problem?id=1125

 

poj 1125这道题,题意为,找到所有可行路径(即从源点可到达所有其他的点,注意是有向图,所以必须要以)中,相距最远两点的距离最小。解法当然就是求最短路,分别用dijkstra,bellman_ford,spfa进行求解,但可惜这题数据实在太弱,时间都是0ms

 

简要概括三种最短路算法,也算一个学习小结

 

dijkstra 单源最短路径

不能存在负权边,复杂度为O(n*n),求源点s到任意点的最短距离,d[i]表示源点s到i的最短路

初始:d[s]=0,d[i]=无穷大(i!=s)

 

bellman_ford 单源最短路径

可以存在负权边,但不能出现负权回路。可以找到图中是否存在负权回路。复杂度为O(VE) 

求源点s到任意点的最短距离,d[i] 表示源点s到i的最短距离

判断负权回路:在v-1次松弛后,如果还能进行松弛,则存在负权回路

初始:d[s]=0,d[i]=无穷大(i!=s)

 

spfa 最短路加速算法

是bellman_ford的一种队列实现,减少了很多冗余的计算。初始时将源加入队列。每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。直到队列为空时算法结束。复杂度为O(KE),K平均来说不超过2

判断负权回路:若某一个节点i入队的次数超过v次,则存在负权回路(v为节点的个数)

初始:d[s]=0,d[i]=无穷大(i!=s)

         v[s]=true,v[i]=false(i!=s)

         q.push(s)

 

 

 

三个算法的源代码实现如下:

 

/*dijkstra*/

 

const int INF=(1<<30)-1;

const int N=110;

int n;

int path[N][N];

int start;

int ans;

void dijkstra(int s)

{

int d[N];

bool v[N];

for(int i=1;i<=n;i++)d[i]=INF;

d[s]=0;

memset(v,false,sizeof(v));

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

{

int Min=INF;

int mark=-1;

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

  if(!v[j]&&d[j]<Min){Min=d[j];mark=j;}

if(mark==-1)break;//每次循环都会加入一个新的节点,当某一次找不到新节点时,则不存在s到所有点的最短路

v[mark]=true;

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

  if(!v[j]&&d[j]>d[mark]+path[mark][j])d[j]=d[mark]+path[mark][j];

}

 

}

 

 

 

/*bellman_ford*/

 

const int INF=(1<<30)-1;

const double EPS=1e-8;

const int N=110;

struct E

{

      int u,v,path; 

}e[N*N];

int ans;

int k;

int n;

int num;

void bellman_ford(int s)

{

     int d[N];

     for(int i=1;i<=n;i++)d[i]=INF;

     d[s]=0;

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

     {

        bool flag=true;

        for(int j=0;j<num;j++)//每次都用所有的边(无向图则算两条边)进行松弛

         if(d[e[j].v]>d[e[j].u]+e[j].path)

         {flag=false;d[e[j].v]=d[e[j].u]+e[j].path;}    

        if(flag)break ;   //提前结束循环

     }

 

     for(int j=0;j<num;j++)//判断负权回路

         if(d[e[j].v]>d[e[j].u]+e[j].path)

           存在负权回路;

}

 

 

 

/*spfa*/

const int INF=(1<<30)-1;

const double EPS=1e-8;

const int N=110;

int path[N][N];

int ans;

int k;

int n;

void spfa(int s)

{

     int d[N];

     bool v[N];

     for(int i=1;i<=n;i++)d[i]=INF;

     d[s]=0;

     memset(v,false,sizeof(v));

     v[s]=true;

     queue<int> q;//队列

     q.push(s);

     while(!q.empty())//队列为空,松弛结束

     {

       int t=q.front();

       q.pop();

       v[t]=false;

       for(int i=1;i<=n;i++)//用队首节点t对与它相邻的边,进行松弛

       {

         if(d[i]>d[t]+path[t][i])//如果松弛成功,且与t相邻的节点i不在队列中,则i入队

         {

           d[i]=d[t]+path[t][i];

           if(!v[i]){q.push(i);v[i]=true;}                               

         }        

       }                                

     }       

}

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值