搜索
查看: 2403|回复: 1
打印 上一主题 下一主题

[啊哈!算法] [图论]一个叫做SPFA的东西(已更新)

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-20 20:58:32 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

输入样例:
5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4
4 5 5
5 3 6

输出样例:
0 2 5 9 9

代码1(使用了边集数组!):

  1. /* Author: Hahahuo
  2. * Date: 10,11,2011
  3. * City: Wuhan
  4. * Website: www.ahalei.com
  5. * Title: SPFA (Shortest Path Faster Algorithm)
  6. * Tips: 1.SPFA算法是西南交通大学段凡丁于1994年发表的。
  7. *       2.小提示:个人认为,ahalei画的图非常好,数据也很好。
  8. *                 为什么呢?因为M≠N。大家调试的时候,第一件事,就是检查M和N是否写反了。
  9. *                           去年NOIP时候,我就是因为这件事浪费了非常多的时间。现在大部分测试中,图论题一定给的是N=M!
  10. *                           (这是出题的技巧!)
  11. */
  12. #include<cstdio>
  13. #include<iostream>
  14. #include<queue>//C++_STL 标准模板库
  15. #define MAXN 100+1
  16. #define MAXM 100+1
  17. using namespace std;
  18. int n,m;
  19. int dis[MAXN];
  20. bool book[MAXN];
  21. struct edge//边
  22. {
  23.         int start;
  24.         int end;
  25.         int length;
  26. }map[MAXM];//边集数组,将时间复杂度降至O(2M)
  27. struct point
  28. {
  29.         int start;
  30.         int end;
  31. }points_to_edges[MAXN];//表示以某个点为起点的边 是从第几号边 到第几号边
  32. int cmp(const void *x,const void *y)
  33. {
  34.         return (*(edge *)x).start - (*(edge *)y).start;
  35. }//small to big
  36. void input()
  37. {
  38.         scanf("%d %d",&n,&m);
  39.         for(int i=1;i<=m;i++)
  40.                 scanf("%d %d %d",&map.start,&map.end,&map.length);
  41.         return;
  42. }
  43. void output()
  44. {
  45.         for(int i=1;i<=n;i++)
  46.                 printf("%d ",dis);
  47.         printf("\n");
  48.         return;
  49. }
  50. void init_map()
  51. {
  52.         qsort(&map[1],m,sizeof(map[0]),cmp);
  53.         for(int i=1;i<=m;i++)
  54.         {
  55.                 if(map.start!=map[i-1].start)
  56.                         points_to_edges[ map.start ].start = i;
  57.                 if(map.start!=map[i+1].start)
  58.                         points_to_edges[ map.start ].end = i;
  59.         }//构建数组
  60.         return;
  61. }
  62. void spfa()
  63. {
  64.         for(int i=2;i<=n;i++)
  65.                 dis=2000000000;
  66.         queue <int> que;
  67.         book[1]=true;//每次查找一遍是否在队中,非常浪费时间复杂度。
  68.         que.push(1);//将第一个点入队
  69.         while(!que.empty())
  70.         {
  71.                 int cur = que.front();
  72.                 for(int i=points_to_edges[ cur ].start; i<=points_to_edges[ cur ].end; i++)
  73.                         if(dis[ map.end ] > dis[cur] + map.length)
  74.                         {
  75.                                 dis[ map.end ] = dis[cur] + map.length;//松弛成功
  76.                                 if(!book)//该点不在队中,则入队
  77.                                 {
  78.                                         book=true;
  79.                                         que.push(i);
  80.                                 }
  81.                         }
  82.                 book[cur]=false;//出队
  83.                 que.pop();
  84.          }
  85. }
  86. int main()
  87. {
  88.         input();
  89.         init_map();
  90.         spfa();
  91.         output();
  92.         return 0;
  93. }
复制代码



代码2(普通版太阳型spfa):
  1. // Author: Ahalei
  2. // Date: 11 1, 2010
  3. // City: Wuhan
  4. // Website: www.ahalei.com
  5. // Title: SPFA (Shortest Path Faster Algorithm)
  6. // Tips: SPFA算法是西南交通大学段凡丁于1994年发表的

  7. #include <stdio.h>
  8. #define MAX 999
  9. int main()
  10. {
  11.     //文件输入输出
  12.     freopen("spfa.in","r",stdin);
  13.     freopen("spfa.out","w",stdout);
  14.     //
  15.     int E[6][6]={0},dis[6]={0},book[6]={0};
  16.     int que[11]={0},top,bottom;
  17.     int i,j,n,m,x,y,cur;

  18.     scanf("%d %d",&n,&m);

  19.     //初始化边的关系,这里很重要,否则会出错
  20.     for(i=1;i<=n;i++)
  21.         for(j=1;j<=n;j++)
  22.         {
  23.             if(i==j)
  24.                 E[j]=0;
  25.             else
  26.                 E[j]=MAX;
  27.         }

  28.     //读入边   
  29.     for(i=1;i<=m;i++)
  30.     {
  31.         scanf("%d %d",&x,&y);
  32.         scanf("%d",&E[x][y]);      
  33.     }

  34.     //1号顶点到其余各定点的距离的初始化
  35.     dis[1]=0;
  36.     for(i=2;i<=n;i++)
  37.     {
  38.         dis=MAX;
  39.     }
  40.     //队列初始化
  41.     top=1;
  42.     bottom=0;
  43.     //1号顶点入队
  44.     bottom++;
  45.     que[bottom]=1;
  46.     //标记1号顶点已经入队
  47.     book[1]=1;
  48.     while(top<=bottom)
  49.     {
  50.         //当前需要扩展的顶点
  51.         cur=que[top];
  52.         //扫描当前顶点所有的边
  53.         for(i=1;i<=n;i++)
  54.         {
  55.             //dis表示1号顶点到第i号顶点的距离
  56.             //dis[cur]表示1号顶点到当前队列中top指向的顶点顶点(也就是当前正在扩展的顶点)的距离
  57.             //E[cur]表示当前顶点到i号顶点的距离
  58.             if(E[cur]!=MAX)//如果cur和i两个节点之间有边的情况下
  59.             {
  60.                 if(dis>dis[cur]+E[cur])
  61.                 {
  62.                     //如果1号顶点到当前顶点的距离 >当前顶点的距离+当前顶点到i号顶点的距离
  63.                     //说明1号顶点到 i顶点 的距离,通过当前顶点(cur)到i顶点这条边 ,距离被减少了。这里称作松弛成功。
  64.                     dis=dis[cur]+E[cur];//更新 1号顶点到 i顶点 的距离
  65.                     if(book==0)//这的book数组用来判断i号顶点是否在队列中,否则每次都从队列的top到bottom扫描一遍太麻烦了。
  66.                     {
  67.                         //为0表示不在队列中,则将i号顶点加入到队列里。
  68.                         //下面两句是入队操作
  69.                         bottom++;
  70.                         que[bottom]=i;
  71.                         //同时标记i号顶点已经入队
  72.                         book=1;
  73.                     }  
  74.                 }
  75.             }
  76.         }
  77.         //当前顶点出队
  78.         book[cur]=0;//标记当前顶点出队
  79.         //出队操作
  80.         top++;   
  81.     }

  82.     //输出i号顶点到其余各个顶点的距离
  83.     for(i=1;i<=n;i++)
  84.         printf("%d ",dis);

  85.     return 0;
  86. }
复制代码


沙发
小伙伴  发表于 2016-3-8 12:49:28
55行和57行有问题吧
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表