spfa 加 链式前向星存图和遍历

单元最短路算法 但是有可能被卡(什么菊花图啥的)
一般在没有明确负坏的条件下 都是用 效率更高一点的dijkstra算法


链式前向星 是一种以边为存储核心的 存边方法
主要是有以下几个关键的部分
用结构体来存边
至于这个next 因为遍历方法实际上是一个倒序遍历 但是这里却是next我觉得怎么应该用pre呢
next 实际上就是 上一个点的信息
//MAXN 点的数量 MAXM边的数量
struct node
{
    int to,w,next;// to代表去向,w代表边的权值,next记录当前这个点上一个的边出现的位置
}edge[MAXM];// 边的数量
int cnt;// 用来记录边的数量
int head[MAXN];// 记录 以某一点为起点的边出现的位置
//这个head数组的初始化为0还是-1都是开始的 相应的要把第一条变得编号变成1或0就可以了
int vis[MAXN];
int dis[MAXN];
int usetime[MAXN];//使用次数
void add(int u,int v,int w)//加边函数
{
    edge[++cnt].to=u;
    edge[cnt].w = w;
    edge[cnt].next = head[u];//上一次还没更新前的位置
    head[u] = cnt;
}

int spfa(int s)// 队列实现 链式前向星存边 spfa 通过遍历顶点来完成
{
    queue<int>q;
    q.push(s);
    dis[s] = 0;
    //usetime[s] = 1;
    vis[s] = 1;
    while(!q.empty())
    {
        int top = q.front();
        q.pop();
        vis[top] = 0;
        usetime[top]++;
        if(ustime[top] > n)
            return 0;// 某一个点的入队次数大于点的个数 存在负坏
        for(int i = head[top];i != 0;i = e[i].next)// 有负环他就可以无线松弛 然后 入队 次数一定会大于n的
        {
            if(dis[e[i].to] > dis[top] + e[i].w)
            {
                dis[e[i].to] = dis[top] + e[i].w;// 松弛操作
                if(!vis[e[i].to)
                {
                    vis[e[i].to] = 1;
                    q.push(e[i].to)
                }
            }    
        }
    }
    return 1;
}
这样就可以通过spfa来求出最短路 以及 是否存在负环了
int main()
{
    int u,v,w,s;    //u--->v的权值为w,s为起始点
    cin >> n >> m >> s;
    memset(dis,inf,sizeof(dis));
    for(int i = 0;i < m;i++){
        cin >> u >> v >> w;
        add(u,v,w);
        //add(v,u,w);加不加双向边看题意
    }
    spfa(s);
    for(int i = 1;i <= n;i++){
        if(dis[i] != inf)
            cout << dis[i] << " ";
        else
            cout << "inf" << " ";
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45672411/article/details/104557275