SPFA求负环
\( O(n*m)spfa求负环时间复杂度较高\\ 负环:图中存在一个环,环上个边的权值和为负数\\ 01分数规划\\ 求负环的方法,基于SPFA:\\ (1)统计某个点入队的次数,如果某个点入队n次,则说明存在负环\\ (2)统计当前每个点的最短路所含的边数,如果某点的最短路的边数>=n,则存在负环。\\ 图中的负环不一定从1点点走到,它可以从任何一个位置开始走,走到负环。\\ 处理方法:\\ 1.一开始让所有n个点入队,即假设有一个虚拟源点,源点到n个点的距离为0;\\ 2.为什么dis[N]不用初始化为0x3f3f3f3f,dis[N]可以任意初始化\\ 因为,如果存在一个负环<==>某些点到虚拟源点的距离是(—无穷),\\ 因为w[i]是有限值,spfa每在负环上转一圈,dis都会减一个有限值,\\ 但是,dis[负环]上的点会变成负无穷,所以spfa一定会在某个点满足判断负环条件的时候退出\\ 3.floyd和bellman-ford中0x3f3f3f3f/2的问题,如果1号点和其他点不连通,2->3,3会被2更新成0x3f3f3f3f-x\neq0x3f3f3f3f 当所有点入队次数超过2n时,我们认为图中很大可能存在负环。(取巧做法) \)
/*
每个字符串当成一个点,1e5个点,每个字符串相同
对于每个点,该点后可以连任何一个点,n-1
边数为n^2级别
将0~26^2每个十进制数看成一个点,每个字符串看成一条边
从aa-zz编号从0~675,一共676个点
1e5条边.
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=700,M=1e5+10;
int h[N],e[M],ne[M],idx,w[M];
int n,cnt[N];
double dis[N];
char str[M];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
// queue<int>que;
int que[M*100],top;
bool inline check(double mid)
{
memset(st,0,sizeof st);
memset(cnt,0,sizeof cnt);
//memset(que,0,sizeof que);重置top=0即可
memset(dis,0,sizeof dis);
top=0;
for(int i=0;i<676;i++)
{
// que.push(i);
que[++top]=i;
st[i]=true;
}
int Count=0;
while(top!=0)
{
// int t=que.front(),que.pop();
int t=que[top--];
st[t]=false;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+w[i]-mid)
{
dis[j]=dis[t]+w[i]-mid;
cnt[j]=cnt[t]+1;
if(++Count>=10000)return true;
if(cnt[j]>=N)
return true;
if(!st[j])
{
// que.push(j);
que[++top]=j;
st[j]=1;
}
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n),n)
{
memset(h,-1,sizeof h);
idx=0;
for(int i=0;i<n;i++)
{
scanf("%s",str);
int len=strlen(str);
if(len>=2){
int left=(str[0]-'a')*26+str[1]-'a';
int right=(str[len-2]-'a')*26+str[len-1]-'a';
add(left,right,len);
}
}
if(!check(0))//将M==0代入,没有正环
cout<<"No solution"<<endl;
else
{
double l=0,r=1000;
while(r-l>1e-4)
{
double mid=(l+r)/2;
if(check(mid))
l=mid;
else
r=mid;
}
// cout<<l<<endl;
printf("%lf\n",r);
}
}
return 0;
}
坑点,memest()的时间复杂度是O(n)的,在多组测试数据中,使用for初始化比memset要快