基础:
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;
}