POJ-1511 初探Bellman-Ford,再水SPFA模板题..

  昨天狐狸大大交流~~会了bellman-ford..

   bellman-ford简单概括就是:

     /* 

           d [ i ]  来记录源点到 i 点的最小距离,初始值源点的 d [ ] 为0,其他的点为一个足够大的数 

          line[ ] .start 表示线段的起点, line[ ] .end 表示线段的终点, line[ ] .w 表示线段的权值, 

    */

      for ( times=1 to NumOfPoint )

        for ( i = 1 to NumOfLine ) 

           relax ( line[ i ] )

     其核心就在 ralex ,    

          relax 

         {

                 d [ line[i].end ] = min (    d [ line[i].end ]  ,  d [ line[i].start ] + line[ i ] .w ) 

         }

   思想有点类似kruscal..但其每次都是扫描所有的边…写的话..5行之内搞定…但是有tick就是如果题目没有强调…要判断有没有负环…有负环的话那么是无解的..因为可以无限爱负环上转圈而使得值无限的小…

  SPFA是在bellman-ford上的改进…因为bellman-ford每次都要扫描所有的边..这是很浪费的..因为大部分的边并没有更新..SPFA则用一个队列 ( 其实也没必要是队列..甚至是个无序的集合都行,目的是标记当前更新过但还未拓展的点 ) 优化…

  思想就是如果更新了一个点..那么如果有新更新..那肯定和这个更新的点有关…这样就能大大的减少不必要的扫描…每次更新了一个点后.. 将这个点入队…后面当队首到达这个点时,这个点出队..并扫面这个点为起点的所有边来更新…注意的是队列里同一个点只能出现一次…但一个点是可能多次入队的…因为通过这个点更新了相邻的..反过来这些相邻的点在后面的更新中可能又能来更新这个点.. (这个过程用一个bool数组来维护…入队时标记为true..出队之前对其有更新就入不了队…当出队时..则讲其又还原为false..那么后面如果又更新到了…还能入队..)

   介于每次都是更新时扫面的是某点为起点的所有线段…那自然想到用前向星的方式来存储边最方便…即省了空间又高度符合所要做的操作…

   POJ1151 题目的意思抽象出来就是给一个有向图..求 1到所有点的最小距离之和与所有点到1最小距离之和相加的最小值….用一个正向的原图做一次SPFS..再将所有边反过来做一次SPFS..轻轻松松鸭梨不大…..

Program:

#include<iostream>
#include<queue>
#define oo 2000000000000000ll
using namespace std;
struct pp
{
   int x,y,k;    
}line[1000001];
struct pq
{
   int start,end;    
}link[1000001];
int t,p,q,i,j;
long long ans,d[1000001];
bool used[1000001];
queue<int> myqueue;
bool cmp(pp a,pp b)
{
    return a.x<b.x;    
} 
void built()
{
    int i,j,k,h;
    for (i=1;i<=p;i++) 
    {
        link[i].start=0; 
        link[i].end=-1;    
    } 
    i=1;  
    while (i<=q)
    {
        k=line[i].x;   
        link[k].start=i; 
        i++;
        while (i<=q && line[i].x==k) i++;
        link[k].end=i-1; 
    }
}
long long SPFA()
{
    int i,j,h,k;
    long long ans=0;
    memset(used,false,sizeof(used)); 
    for (i=2;i<=p;i++) d[i]=oo;
    d[1]=0;  used[1]=true; 
    while (!myqueue.empty()) myqueue.pop();
    myqueue.push(1);  
    while (!myqueue.empty())
    {
         h=myqueue.front();
         myqueue.pop(); 
         used[h]=false;   
         for (i=link[h].start;i<=link[h].end;i++)
         {
             k=line[i].y;   
             if (d[k]>d[h]+line[i].k)
             {
                 d[k]=d[h]+line[i].k;
                 if (!used[k])
                 {
                     myqueue.push(k);        
                     used[k]=true;            
                 }                        
             }      
         }          
    }
    for (i=2;i<=p;i++) ans+=d[i];
    return ans;
}
int main()
{ 
    scanf("%d",&t);
    while (t--)
    {  
        scanf("%d%d",&p,&q); 
        for (i=1;i<=q;i++) scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].k);
        sort(line+1,line+1+q,cmp);
        built(); 
        ans=SPFA();
        for (i=1;i<=q;i++)
        {
            j=line[i].x;
            line[i].x=line[i].y;
            line[i].y=j;    
        }
        sort(line+1,line+1+q,cmp);
        built();
        ans+=SPFA();
        printf("%I64d\n",ans);
    }
    return 0;   
}

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/kk303/article/details/6852128
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞