//SPFA 算法 今天再偶然的情况下发现了另一种最小路径的方法 正常来说 求最小路径只有两种方法
//gijkstra方法挺好的就是不能处理权值为负的情况 而Ford算法又比较难实现 复杂度高
//首先谈谈我对这个算法的理解吧。这个算法可以处理权值为负数的情况
//但是却没有办法有权值为负的环 这个可以在后面解释 这个和他本身算法有关
//首先用3个一维数组 一个一维数组是用来记录该节点进入队列的次数 如果超过n的话就
//可以证明这个为负权值的环 它就是有点类似BFS 处理与自己相关的节点 如果可以进行松弛
//并且该节点并不在队列里面就放入队列 直到队列为空就结束
//BFS中每一个节点最多就是走一次 但是这里只要你的节点不在队列里面 并且可以松弛的话就可以进入多次
//意味自己如果自身改变的话 就要通过自身改变相关的值
//好了说到现在 其实SPFA的复杂度理论上比FORD要小 KE吧 K就是每个节点进入队列的次数 但是这里说
//每一个节点进入的次数不超过两次就是2K 这个没有证明也就是倍受争议
//所以一般比赛就用dijkstra FORD SPFA一般会被卡死(数据很容易被卡死 但是容易事想)
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=300001;
const int inf =0x7ffffff;
struct edge
{
int from,to,w,next;
}e[1000001];
int head[maxn];
int vis[maxn];
int dist[maxn];
int n,m,t;
void add(int i,int j,int w)
{
e[t].from=i;
e[t].to=j;
e[t].w=w;
e[t].next=head[i];
head[i]=t++;
}
void spfa(int s)
{
queue <int> q;
for(int i=1;i<=n;i++)
dist[i]=inf;
memset(vis,false,sizeof(vis));
q.push(s);
dist[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dist[v]>dist[u]+e[i].w)
{
dist[v]=dist[u]+e[i].w;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
}
memset(head,-1,sizeof(head));
t=0;
//这里比较难理解的应该是把边加入相关数据之中 这个需要一个数组来帮助 这个数组就是说明下一个节点
//gijkstra方法挺好的就是不能处理权值为负的情况 而Ford算法又比较难实现 复杂度高
//首先谈谈我对这个算法的理解吧。这个算法可以处理权值为负数的情况
//但是却没有办法有权值为负的环 这个可以在后面解释 这个和他本身算法有关
//首先用3个一维数组 一个一维数组是用来记录该节点进入队列的次数 如果超过n的话就
//可以证明这个为负权值的环 它就是有点类似BFS 处理与自己相关的节点 如果可以进行松弛
//并且该节点并不在队列里面就放入队列 直到队列为空就结束
//BFS中每一个节点最多就是走一次 但是这里只要你的节点不在队列里面 并且可以松弛的话就可以进入多次
//意味自己如果自身改变的话 就要通过自身改变相关的值
//好了说到现在 其实SPFA的复杂度理论上比FORD要小 KE吧 K就是每个节点进入队列的次数 但是这里说
//每一个节点进入的次数不超过两次就是2K 这个没有证明也就是倍受争议
//所以一般比赛就用dijkstra FORD SPFA一般会被卡死(数据很容易被卡死 但是容易事想)
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=300001;
const int inf =0x7ffffff;
struct edge
{
int from,to,w,next;
}e[1000001];
int head[maxn];
int vis[maxn];
int dist[maxn];
int n,m,t;
void add(int i,int j,int w)
{
e[t].from=i;
e[t].to=j;
e[t].w=w;
e[t].next=head[i];
head[i]=t++;
}
void spfa(int s)
{
queue <int> q;
for(int i=1;i<=n;i++)
dist[i]=inf;
memset(vis,false,sizeof(vis));
q.push(s);
dist[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dist[v]>dist[u]+e[i].w)
{
dist[v]=dist[u]+e[i].w;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
}
memset(head,-1,sizeof(head));
t=0;
//这里比较难理解的应该是把边加入相关数据之中 这个需要一个数组来帮助 这个数组就是说明下一个节点
//是再原来节点的第几个
如果这个节点本来就在对列里面就不需要再次进入栈