算法流程:
关于spfa判断正负环:
注:N为点的数量,M为边的数量
Bellman_Ford在求解最短路时,如果A->B,那么只有dist[A]被更新了以后,dist[B]才有必要被更新,但Bellman_Ford无论如何,都对每条边进行N- 1次松弛操作。
Spfa针对这一点进行优化,如果松弛操作使某个点改变,且这个点不在队列中,就加进队列中。
总共有n个点,因为如果cnt[j] >= n有大于等于n条边时,则证明有n + 1个点,根据抽屉原理说明这条路径有一个点被经过了两次,则成环
可以用这个方法在求最短路的过程中判断负环
因为是在dist数组更新时cnt[]才更新所以说明这个一定是负权环才会导致dist[]变小
求正环同理,转换成最长路即可
SPFA(Shortest Path Faster Algorithm)是一种基于贪心思想的最短路径算法,它可以用于求解带有负权边的图中的单源最短路径问题。在一般的图中,如果存在负权边,那么可能存在负环。负环指的是图中一个环路,使得环路上的所有边的权值之和为负数。如果存在负环,那么最短路径可能不存在,因为可以一直绕着负环不断地降低路径长度,最终得到一个负无穷的路径长度。
SPFA算法可以判断图中是否存在负环,其主要思路是通过对每个点进行多次松弛操作,判断是否存在环路可以不断降低路径长度。具体实现方法是利用一个队列来维护需要进行松弛操作的点,每次取出队头的点,然后更新所有与之相邻的点的距离,如果某个点的距离发生了变化,就把它加入队列中等待后续的处理。如果某个点进队的次数超过了n次(n为图中点的数量),那么就说明存在负环。这是因为在一个无负环图中,任意两点之间的最短路径最多经过n-1条边,如果存在负环,那么可以不断绕着负环降低路径长度,因此在经过n次松弛操作之后,仍然存在点的距离发生了变化,这就意味着存在负环。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int M = 1e5 + 10,N = 26 * 26 + 50;
int h[N],e[M],w[M],ne[M],idx;
int n,cnt[N];
double dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}
bool check(double mid)
{
queue<int> q;
memset(st, 0, sizeof st);
memset(cnt, 0, sizeof cnt);
int count = 0;
for(int i = 0; i < 26 * 26; i ++ )
{
q.push(i);
st[i] = true;
}
while(q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if(dist[j] < dist[t] + w[i] - mid)
{
dist[j] = dist[t] + w[i] - mid;
cnt[j] = cnt[t] + 1;
if(cnt[j] >= N) return true;
if(++count > 10000 )return true;
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
return false;
}
int main()
{
while(scanf("%d", &n), n)
{
char c[1010];
memset(h, -1, sizeof h);
idx = 0;
for(int i = 1;i <= n; i ++ )
{
scanf("%s",c);
int len = strlen(c);
if(len >= 2)
{
int left = (c[0] - 'a') * 26 + c[1] - 'a';
int right = (c[len - 2] - 'a') * 26 + c[len - 1] - 'a';
add(left, right, len);
}
}
if(!check(0))puts("No solution");
else
{
double l = 0,r = 1000;
while( r - l > 1e-4 )
{
double mid = (l + r) / 2;
if(check(mid)) l = mid;
else r = mid;
}
printf("%lf\n",r);
}
}
return 0;
}