SPFA

#include<iostream>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
#define MAXV 10000
#define INF 1000000000 //此处建议不要过大或过小,过大易导致运算时溢出,过小可能会被判定为真正的距离

using std::vector;
using std::queue;

struct Edge{
	int v; //边权
	int to; //连接的点
};

vector<Edge> e[MAXV]; 
int dist[MAXV]; //存储到起始点距离
int cnt[MAXV]; //记录入队次数,超过V则退出
queue<int> buff; //用于记录状态
bool done[MAXV]; //用于判断该节点是否已经在队列中
int V; //节点数
int E; //边数

bool bfs(int s, int f);
int main()
{
    while(cin>>V>>E){
        for(int i = 0; i < E; i++){//首先输入边的信息
            int x, y, l;
            cin>>x>>y>>l;
            Edge  temp1, temp2;
            temp1.v = l;  temp1.to = y;
            temp2.v = l;  temp2.to = x;
            e[x].push_back(temp1);
            e[y].push_back(temp2);//把信息放入到vectore当中
        }
        int s, f;
        cin>>s>>f;//表示要求从s点到f点的最短路

        if(!bfs(s, f)){
            cout<<"No"<<endl;
        }else{
            cout<<"Yes"<<endl;
            cout<<dist[f]<<endl;
        }
    }
    return 0;
}

bool bfs(int s, int f)
{
    memset(cnt, 0, sizeof(cnt));//将元素开始时入队的次数记录为0
    for(int i = 0; i < V; i++)
        dist[i] = INF;
    dist[s] = 0;//将s到其它点的距离都设置为无穷大
    buff.push(s);
    done[s] = true;  cnt[s]++; //记录出发的节点在队列中,并且记录其入队的次数加一

    while(!buff.empty()){//当buff队列不空的时候
        int head = buff.front();//把队头的元素取出来
        for(int i =0; i < e[head].size(); i++){
            int v, y ;
            Edge temp = e[head][i];
            v = temp.v;    y = temp.to;
            if(dist[y] > (dist[head] + v)){
                dist[y] = dist[head] + v;
                if(!done[y]){
                    buff.push(y);
                    done[y] = true;
                    cnt[y]++;
                    if(cnt[y] > V) {//如果存在复权就退出操作
                       while(!buff.empty())//清空队列
                          buff.pop();
                          return false;
                    }//if
                }//if
            }//if
        }//for
        buff.pop();//把队头的元素移出
        done[head] = false;
    }//while

    //注意必须加入这个for()循环,否则没有办法进行多组数据的测试while(cin>>V>>E)
    for(int i = 0; i < V; i++){
        while(!e[i].empty())
            e[i].pop_back();
    }

    return true;
}

由于上周进行周赛的 时候有一道题目是要求隐式最短路问题,里面需要用到SPFA这个算法,于是就去学了一下。我先到网上看了一下关于SPFA算法的思想,了解了它的实现思想,然后自己写了一个。(注:这个是无向图的)解释一下我的代码吧............


关于我定义的一些变量的意思:1.首先头文件中我使用到了STL中的vector和queue,其中vector在这里是一个可变的数组,用来存放与之相邻的点;queue中存放的就是目前的状态。2.同时还定义了一个结构体,用来表示边的信息。3.dist[j]用于存放j点到起始点s的距离,4.cnt[j]用于记录j点进入队列的次数,因为SPFA算法可以检测出图中是否存在负环,而这个判断的标准就是看某个点是否进入队列超过了节点数V次(这点的证明大家可以去参考其它的资料)。5.done[j]用于表示j点是否在队列中。


主函数:1.首先输入节点的个数V和边的条数E。2.接着输入E条边,并存放到可变数组vector中,然后再调用bfs()函数,判断是否存在最短路,若存在则输出最短路,否则输出'No'。


bfs()函数:1.首先将起始点放入队列中。2.while(!buff.empty()){}循环是重点,这里我们从队列中取出第一个元素,然后从这个点开始看它所能连接到的点是否能够进行松弛操作,如果可以的话就对距离dist[]进行更新。注意一点就是只有能够更新,并且那个该点不在队列中才把它放入到队列中。开始的时候我没有考虑到这个问题,直接将能够更新的点放入队列中,这样导致了很多重复操作,而且结果是错误的。(这一点大家可以自己设置一些数据去测试一下)3.把点放到队列中以后要判断它是否已经进入到队列中超过了V次,如果超过则说明存在负环,也就没有最短路了。4.然后把队头的元素弹出。5.注意最后一个for()循环是用来清空队列的,因为之前把队列定义为了全局变量,所以如果不清空队列就没有办法进行多组数据的测试。我之前就出现过单组数据测试正确,但是多组数据测试错误的情况,就是由于没有考虑到这点造成的。6.s点到f点的最短路就存放在dist[f]中。(前提是存在)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值