#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<vector>
using namespace std;
const int inf=0x7f7f7f7f;
const int NUM_NODE=310;
struct edge{ // 边的数据结构
int to;int weight;
edge(int t,int w):to(t),weight(w){}
};
vector<edge> e[NUM_NODE];
int dist[NUM_NODE];
bool spfa(int s){ // s是源点
memset(dist,inf,sizeof(dist)); // 距离初始化为正无穷
dist[s]=0; // 源点到自己距离为0
bool inqueue[NUM_NODE]; // 用来记录顶点是否入队
memset(inqueue,0,sizeof(inqueue));
int qtimes[NUM_NODE]; // 用来记录入队次数
memset(qtimes,0,sizeof(qtimes));
queue<int> q;
q.push(s);inqueue[s]=true;++qtimes[s]; // 将源点入队
int cur;
while(!q.empty()){ // while队列非空
cur=q.front();q.pop();inqueue[cur]=false; // 取出队首
for(edge i:e[cur]) // 对每一个队首邻接的顶点
if(dist[i.to]>dist[cur]+i.weight){ // 如果经过队首会让你更近一些
dist[i.to]=dist[cur]+i.weight; // 那么就更新距离
if(!inqueue[i.to]){
q.push(i.to);inqueue[i.to]=true;++qtimes[i.to]; // 入队
if(qtimes[i.to]>NUM_NODE)return false; // 入队次数>顶点数,出现负环
}
}
}
return true; // 没有负环
}
int main(){
ios::sync_with_stdio(false);
}
/*
SPFA可以处理负边,在稠密图里不如dijkstra。
复杂度是O(kE),k是每个点的平均进队次数。
1. 初始时,只有起点在队列中。
2. 遍历与起点相连的边,如果可以松弛就更新距离dist[],然后判断这个点在不在队列里,如果不在就入队标记。
3. 取出队首,取消标记,循环2-3步,直至队为空。
如何判断成环:
在储存边时,记录下每个点的入度,每个点入队的时候记录一次。
如果入队的次数大于这个点的入度,说明从某一条路进入了两次,即该点处成环。
如何判断负环:
一条最短路径最多通过所有顶点,即松弛n次,不可能从某些顶点绕好几圈。
因此,如果某个节点入队次数>n,则出现负环。
*/