SPFA算法 poj 1364

求单源最短路的SPFA算法的全称是:ShortestPath Faster Algorithm。 最短路径快速算法-SPFA算法是西南交通大学段凡丁于1994年发表的。

适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。我们约定有向加权图G不存在负权回路,即最短路径一定存在。当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点。

算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。

实现方法:

  建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。

判断有无负环:

  如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)

poj 1364

题目意思就是给定一串数的长度,,然后给出一段子序列,并给出子序列的条件,然后问是否存在这样的子序列

不难看出,从给定的各个条件,比如 给定 u,v,s,w

我们用dis[i]表示从开始到现在i-1个元素的和,那么给定的子序列就是dis[u+v-1]-dis[u]

正好给定的每个条件都是dis[i]>dis[j]+w,小于反过来就行了,貌似和差分约束很相似,

其实题目说了w是个整数,所以可以转为>=w+1

然后就可以用差分约束做了。

关于差分约束,我也从网上看了一些整理了一篇。可以参考一下

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
using namespace std;
const int N = 103;
struct node{
int v;
int w;
node(int vv =0,int ww =0):v(vv),w(ww){}


};
int dis[N];
int c[N];
bool visit[N];
vector<node>  a[N];
int n,m;
const int INF = 9999999;
bool spfa(){
for(int i = 1;i<=n+1;i++)dis[i] = INF;
memset(visit,false,sizeof(visit));
memset(c,0,sizeof(c));
dis[0] = 0;
visit[0] = true;
queue<int> qe;
qe.push(0);
c[0]++;
while(!qe.empty()){
int cur = qe.front();
qe.pop();
visit[cur] = false;
for(int i = 0;i<a[cur].size();i++){
if(dis[a[cur][i].v]>dis[cur]+a[cur][i].w){
dis[a[cur][i].v] = dis[cur]+a[cur][i].w;
c[a[cur][i].v]++;
if(c[a[cur][i].v]>n)return false;
if(!visit[a[cur][i].v]){
qe.push(a[cur][i].v);
visit[a[cur][i].v] = true;
}
}
}
}
return true;
}
int main()
{
while(scanf("%d",&n),n!=0){
scanf("%d",&m);
int u,v,w;
char  s[10];
for(int i = 0;i<N;i++)a[i].clear();
for(int i = 0;i<m;i++){
scanf("%d%d%s%d",&u,&v,s,&w);
if(strcmp(s,"gt")==0){
a[u+v+1].push_back(node(u,-w-1));
}else {
a[u].push_back(node(u+v+1,w-1));
}
}
for(int i=1;i<=n;++i)a[0].push_back(node(i,0));
if(spfa()){
printf("lamentable kingdom\n");
}else printf("successful conspiracy\n");
}
return 0;
}

注意哦,总共有n+2个顶点,我就是在初始化是老是以为是n+1个顶点,结果wa了很多次,大家注意哦。。。


你可能感兴趣的:(Algorithm,c,算法,优化,struct,交通)