最短路——Spfa算法

该算法使用一个队列进行维护,最初将源点加入到队列,每次取出一个元素,并且对与其相邻的点都进行松弛,若某个点松弛成功再入队,vis数组是表示在队内的元素。


定义部分:

const int Max = 0x3f3f3f3f;
int poi_num, edge_num, cnt;

struct edge{    //链式前向星的边结构体
    int v;
    int nex;
    int len;
}e[105];

int id[105];    //i为起点的第一条边的位置
int d[105];     //起点到第i个点的距离
bool vis[105];      //队列内的数
int Time[105];      //每个点的松弛次数,判断负环

加边函数:

void add(int bgn, int nd, int len){     //无向图加两遍
    e[cnt].v = nd;
    e[cnt].len = len;
    e[cnt].nex = id[bgn];
    id[bgn] = cnt++;
}

初始化部分:

void init(){
    //id归位-1
    for(int i = 0; i <= poi_num; i++){
        id[i] = -1;
    }
    cnt = 0;
    for(int i = 0; i <= poi_num; i++){
        d[i] = Max;
    }
    memset(vis, 0, sizeof(vis));
    memset(Time, 0, sizeof(Time));
}

算法部分:

bool spfa(int x){
    vis[x] = 1;
    queue<int> q;
    q.push(x);
    d[x] = 0;
    bool flag = false;
    while(!q.empty()){
        int t = q.front();
        q.pop();
        for(int i = id[t]; ~i; i = e[i].nex){
            if(d[e[i].v] > d[t] + e[i].len){
                d[e[i].v] = d[t] + e[i].len;
                if(!vis[e[i].v]){
                    vis[e[i].v] = 1;
                    Time[e[i].v]++;
                    if(Time[e[i].v] > poi_num){
                        flag = true;
                    }
                    q.push(e[i].v);
                }
            }
        }
        vis[t] = 0;
    }
    if(flag){
        return flag;
    }
    else{
        return flag;
    }
}

完整代码:

#include 
#include 
#include 
using namespace std;

const int Max = 0x3f3f3f3f;
int poi_num, edge_num, cnt;

struct edge{
    int v;
    int nex;
    int len;
}e[105];

int id[105];
int d[105];
bool vis[105];
int Time[105];

void add(int bgn, int nd, int len){
    e[cnt].v = nd;
    e[cnt].len = len;
    e[cnt].nex = id[bgn];
    id[bgn] = cnt++;
}

void init(){
    for(int i = 0; i <= poi_num; i++){
        id[i] = -1;
    }
    cnt = 0;
    for(int i = 0; i <= poi_num; i++){
        d[i] = Max;
    }
    memset(vis, 0, sizeof(vis));
    memset(Time, 0, sizeof(Time));
}

bool spfa(int x){
    queue<int> q;
    vis[x] = 1;     //起点先放入队列内
    q.push(x);
    d[x] = 0;       //起点到自身的距离为0
    bool flag = false;      //首先认为没有负环
    while(!q.empty()){
        int t = q.front();      //取队首元素并pop
        q.pop();
        for(int i = id[t]; ~i; i = e[i].nex){       //遍历所有的边
            if(d[e[i].v] > d[t] + e[i].len){        //对这个点邻接的点松弛
                d[e[i].v] = d[t] + e[i].len;
                if(!vis[e[i].v]){       //如果不在队列内就加入
                    vis[e[i].v] = 1;
                    Time[e[i].v]++;     //松弛次数增加
                    if(Time[e[i].v] > poi_num){
                        return 1;
                    }
                    q.push(e[i].v);
                }
            }
        }
        vis[t] = 0;     //从队列中取出
    }
    return 0;
}
int main(){
    int poi_bgn, poi_nd, edge_len;
    scanf("%d %d", &poi_num, &edge_num);
    init();
    for(int i = 0; i < edge_num; i++){
        scanf("%d %d %d", &poi_bgn, &poi_nd, &edge_len);
        add(poi_bgn, poi_nd, edge_len);
        add(poi_nd, poi_bgn, edge_len);
    }
    scanf("%d %d", &poi_bgn, &poi_nd);
    if(spfa(poi_bgn)){
        cout << (-1) * 0x3f3f3f3f << endl;
    }
    else{
        cout << d[poi_nd] << endl;
    }
    return 0;
}

你可能感兴趣的:(最短路)