模板_SPFA_链式前向星

//
#include<bits/stdc++.h>
using namespace std;

const int INF=0x3f3f3f3f;
const int N=1e6+7;          // 点
const int M=2e6+7;          // 边
int n,m;

int h[N],pos;               // h[N] 定位边 // pos e[]下标推进
struct edge{ int y,data,next; }e[M];

void init()
{
    pos=0;
    for( int i=0;i<N;i++ ) h[i]=-1;         // 点init
    for( int i=0;i<M;i++ ) e[i].next=-1;    // 边init
}

void add( int x,int y,int data )
{
    e[pos].y=y;
    e[pos].data=data;
    e[pos].next=h[x];           // 定位之前边
    h[x]=pos++;                 // 定位当前边
}

int dis[N];                 // dis[i]: start to i  
bool inq[N];                // inq[i]=true: i在队列中
int ne[N];                  // 判断负圈
int dad[N];                 // 打印路径

int SPFA( int start )       // 返回1表示出现负圈
{
    int i,x,y,data;

    memset( dis,0x3f,sizeof( dis ) );   // for...
    memset( inq,0,sizeof( inq ) );
    memset( ne,0,sizeof( ne ) );        // init
    
    dis[start]=0;                      	// 起点 到自己的距离是0
    inq[start]=1;                     	// 起点 在队列中
    ne[start]=1;                        // 起点 入过一次队列
    queue<int> q; q.push( start );
    
    while( !q.empty() )
    {
        x=q.front(); q.pop(); inq[x]=0;     // 队头出队

        for( i=h[x];~i;i=e[i].next )        // 前向星遍历
        {
            y=e[i].y; 
            data=e[i].data;
            if( dis[y] > dis[x]+data )      // 直达 > 松弛 直达要更新
            {
                dis[y]=dis[x]+data;
                dad[y]=x;
                if( !inq[y] )               // y更新了 且y不在队列里
                {
                    q.push(y); inq[y]=1; ne[y]++; 
                    if( ne[y]>=n ) return 1;        // ">" vs ">=" ?
                }                                   // use_n
            }
        }
    }
    return 0;
}

void out( int x,int y )                     // 打印路径
{
    if( x==y ) { cout<<x<<" "; return ; }
    out( x,dad[y] ); cout<<y<<" ";
}

int main()
{
    int start,x,y,data,i;

    while( cin>>n>>m>>start )
    {
        init();
        if( n==0 && m==0 ) break;

        while( m-- )
        {
            cin>>x>>y>>data;
            add( x,y,data );    // 无向边
            add( y,x,data );
        }
        SPFA( start );          // 计算 起点start 到其他所有点的最短路

        for( i=1;i<=n;i++ )
        {
            cout<<dis[i]<<endl;
            cout<<"path:"; out( start,i ); cout<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_63173957/article/details/124727899