ACM_SPFA算法

来源:互联网 发布:全国软件测试大赛 编辑:程序博客网 时间:2024/06/03 21:03

SPFA算法:首先源点到源点的距离为0,然后用源点对其他点进行松弛操作(更新操作),若松弛成功,表明源点到其的路径变小了,那么该点有可能能作为中间点松弛其他点,所以得将其入队列(如果它不在队列里面的话)某个点得到了松弛,如果它在队列里面,那么它能松弛的点会在接下的过程中得到松弛,如果它在这之前已经松弛了其他点,那么由于它受到了松弛,则那些它可以松弛的点将会进一步被松弛,所以它得重新入队列;如果没有负权值的边,那么松弛操作不会一直下去,当队列里的元素为空时,算法结束!

#include<cstdio>#include<iostream>#include<queue>#include<cstring>using namespace std;#define len 100#define INF 9999999int n,m,s,d,dis[len],vis[len],road[len][len],cot[len];//n个点,m条边,s源点,d终点;dis[i]->s到i的最短距离,//vis[i]判断i是否在队列中,road数组存图,cot[i]表示i进//队列的次数,也就是i更新dis数组的次数bool spfa(){    int i,t;;    for (i = 1; i <= n; ++i)        dis[i] = INF;//初始时,源点到其他点的距离为无穷大    memset(vis,0,sizeof(vis));    memset(cot,0,sizeof(cot));    queue<int>q;    q.push(s);    dis[s] = 0;    vis[s] = 1;    while (!q.empty())    {        t = q.front();        q.pop();        vis[t] = 0;        ++cot[t];        if (cot[t] > n)            return false;        for (i = 1; i <= n; ++i)        {            if (dis[i] > dis[t] + road[t][i])/*假设1,2之间存在负权值的边,如果1(或2)为源点,那么当i=2时,dis[2]更新(无穷大->负值),2入队列;当2出队列,i=1时,dis[1]被更新(0->负值),1入队列,2被更新......那么对列将不会为空*/            {                dis[i] = dis[t] + road[t][i];                if (!vis[i])                {                    q.push(i);                    vis[i] = 1;                }            }        }    }    return true;}int main(){    int i,j,u,v,w;    while (cin>>n>>m)    {        for (i = 1; i <= n; ++i)        {            for (j = 1; j <= n; ++j)                road[i][j] = i == j ? 0 : INF;        }        for (i = 1; i <= m; ++i)        {            scanf("%d%d%d",&u,&v,&w);            road[u][v] = road[v][u] = w;        }        scanf("%d%d",&s,&d);        if (spfa())        {            cout<<dis[d]<<endl;        }        else            cout<<"sorry"<<endl;    }    return 0;}


0 0