acm专题学习之最短路(三)SPFA算法+UVa558_Wormholes

基础:

Bellman-Ford算法:是求含负权图的单源最短路径的一种算法,也可以用来判断是否具有负权环。

Bellman-Ford实现思路:和dij有点类似,使用dis[ ]数组(更新记录每个点到起点s所需要的最短路),per[ ]数组(用来记录最短路每个点的父结点)。进行n-1(点的个数-1)次的松弛操作(对dis[ i ]进行修改),如果n-1次松弛过后,还能够再进行松弛,就说明含有负权回路。

SPFA算法:

SPFA算法:Bellman-Ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。

SPFA实现思路:使用dis[ ]数组(更新记录每个点到起点s所需要的最短路),per[ ]数组(用来记录最短路每个点的父结点,记录最短路),vis[ ](数组用来标记是否已经在队列里面)。进行队列操作,先把起点放进去,每次出列队头,将与队头相连的点进行松弛操作。如果相连的该点,能够更新dis且不在队列中,就另其入队,如果已经在队列里面就不用入队。如果某一点进入队列的次数大于等于 n,则存在负权回路,其中 n 为图的顶点数。

UVa558_Wormholes:

题目:单向路径,路径有正有负,问是否存在负环

思路:SPFA算法求负环

代码:

#include <algorithm>
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn=1000+15;
const int inf=0x3f3f3f3f;
int n,m;
int u,v,w;
int dis[maxn];//更新记录每个点到起点s所需要的最短路
bool vis[maxn];//用来标记是否已经在队列里面
int head[maxn];//用来记录和坐标i链接的点(记录了其中一个链接点,然后用mp里面的nxt找到剩余链接的点)
int cnt[maxn];//记录坐标已经进入队列多少次了
struct node
{
    int v,w;//相连的点,花费
    int nxt;//上一个与相同head下标相连的点
} mp[maxn*2];//地图
int count1;
void add(int u,int v,int w)//添加边
{
    mp[count1].nxt=head[u];//上一个与相同head下标相连的点
    mp[count1].v=v;
    mp[count1].w=w;
    head[u]=count1++;
}
bool spfa(int u)
{
    queue<int>que;
    for(int i=0; i<n; i++)
    {
        dis[i]=inf;
        vis[i]=0;
        cnt[i]=0;
    }
    que.push(u);
    vis[u]=1;
    cnt[u]++;
    dis[u]=0;
    while(que.size())
    {
        int u=que.front();
        que.pop();
        vis[u]=0;
        for(int i=head[u]; i!=-1; i=mp[i].nxt)//遍历所有和u相连的点
        {
            int v=mp[i].v;
            if(dis[v]>dis[u]+mp[i].w)
            {
                dis[v]=dis[u]+mp[i].w;
                if(!vis[v])
                {
                    cnt[v]++;
                    if(cnt[v]>=n)//某一点进入队列的次数大于等于 n,则存在负权回路
                    {
                        return true;
                    }
                    vis[v]=1;
                    que.push(v);
                }
            }
        }
    }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        count1=0;
        memset(head,-1,sizeof(head));//设置-1是因为坐标最小是0
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        bool flag=spfa(0);
        if(flag)
            printf("possible\n");
        else
            printf("not possible\n");
    }
    return 0;
}

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值