记ben最喜欢的SPFA

About SPFA

本文记录一些咱搞过的一些SPFA的瞎搞,并不是SPFA的入门教程


单源最短路径

每次依一个与队长有关的概率随机排序队列, cmp 函数直接写按 dis 排序就行

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int M = 5e5 + 10, N = 1e5 + 10;
struct node{
	int nxt,v,w;
}g[M];
int head[N],tot,lgg; 
void add(int u,int v,int w){
	g[++tot].v=v;
	g[tot].w=w;
	g[tot].nxt=head[u];
	head[u]=tot;
} 
int n,m,dis[N],t[N],kkk;

bool cmp(int l,int r){
	return dis[l]<dis[r]-kkk;
}

long long ans;
bool vis[N];
std::mt19937 rd(time(0));
int q[N*122];
void SPFA(int s){
	int l=0,r=0;
	for(int i=1;i<=n;i++){
		dis[i]=1e9;
		vis[i]=0;
	}
	dis[s]=0;
	q[l]=s;
	vis[s]=1;
	while(l<=r){
        if(rd()%(((r-l+1>>4)*5)+1)==0)sort(q+l,q+r+1,cmp);
		int u=q[l++];
		vis[u]=0;
		for(int i=head[u];i;i=g[i].nxt){
			int v=g[i].v,w=g[i].w;
			if(dis[u]+w<dis[v]){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					if(l>1) q[--l]=v;
					else q[++r]=v;
					vis[v]=1;
				}
			} 
		}
	}
}

int s;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
		kkk+=w;
	}
	kkk=log2(kkk); 
	SPFA(s);
	for(int i=1;i<=n;i++)
		cout<<dis[i]<<" ";
}  

johnson

这个其实更扯蛋

排序函数改一下,改成按 dis 绝对值带容错排序

容错大概设为 Sdisnm 即可,Sdis 是边权和

#include<bits/stdc++.h>
const signed M = 1e4 + 10, N = 1e4 + 10;	
int kkk;
#define int long long 
using namespace std;

struct node{
	int nxt,v,w;
}g[M];
int head[M],tot,lgg; 
void add(int u,int v,int w){
	g[++tot].v=v;
	g[tot].w=w;
	g[tot].nxt=head[u];
	head[u]=tot;
} 
int n,m,dis[N],t[N];

bool cmp(int l,int r){
	return abs(dis[l])-abs(dis[r])<-kkk*2;
}
std::mt19937 rd(time(0));

long long ans;
bool vis[N];
bool down(){
	int s=0;
	stack<int> q;
	for(int i=1;i<=n;i++){
		dis[i]=1e9;
	}
	dis[s]=0;
	q.push(s);
	vis[s]=1;
	t[s]++;
	while(!q.empty()){
		int u=q.top();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=g[i].nxt){
			int v=g[i].v,w=g[i].w;
			if(dis[u]+w<dis[v]){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					q.push(v);
					vis[v]=1;
					t[v]++;
				}
			}
			if(t[v]>n){
				return 0;
			} 
		}
	}
	return 1;
}
int q[101010];
void SPFA(int s){

	int l=0,r=0;
	for(int i=1;i<=n;i++){
		dis[i]=1e9;
		vis[i]=0;
	}
	dis[s]=0;
	q[l]=s;
	vis[s]=1;
	while(l<=r){
        if(rd()%(((r-l+1)*5)+1)==0)sort(q+l,q+r+1,cmp);
		int u=q[l++];
		vis[u]=0;
		for(int i=head[u];i;i=g[i].nxt){
			int v=g[i].v,w=g[i].w;
			if(dis[u]+w<dis[v]){
				dis[v]=dis[u]+w;
				if(!vis[v]){
				    if(l>1)q[--l]=v;
					else q[++r]=v;
					vis[v]=1;
				}
			} 
		}
	}
}


signed main(){
//	freopen("P5905_11.in", "r", stdin);
//	freopen("sb.txt", "w", stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		add(0,i,0);
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
		kkk+=w;
	}
	kkk=abs(kkk)/n/m;

	if(!down()){
		cout<<-1;
		return 0;
	}
	for(int i=1;i<=n;i++){
		SPFA(i);
		for(int j=1;j<=n;j++){
			ans+=dis[j]*j;
		}
		cout<<ans<<"\n";
		ans=0;
	}
} 

糖果(hack SPFA version)

奇妙,我们注意到这道题排序的意义不大,于是直接改随机化,调参,发现怎么着都会 T

然后我们发现只要带负环我们的复杂度就很容易寄,没有负环是飞快的

那卡时即可

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int M = 5e5 + 10, N = 1e6 + 10;
struct node{
	int nxt,v,w;
}g[M];
int head[N],tot,lgg; 
void add(int u,int v,int w){
	g[++tot].v=v;
	g[tot].w=w;
	g[tot].nxt=head[u];
	head[u]=tot;
} 
int n,m,dis[N],t[N],kkk,tmer;

long long ans;
bool vis[N];
int in[114514];
std::mt19937 rd(time(0));
int q[N*12];
bool SPFA(int s){
	int l=0,r=0;
	for(int i=1;i<=n;i++){
		dis[i]=INT_MAX;
		vis[i]=0;
	}
	dis[s]=0;
	q[l]=s;
	vis[s]=1;
	while(l<=r){
        if(tmer>23550000)return 1;
        
       // if((double)(clock()-F)/1000>940) return 1;
        if(rd()%((((r-l+1)>>3)*53)+1)==0 and rd()%2==0){
			
            int ysuperman=(l+r)>>1;
			random_shuffle(q+ysuperman,q+r);
			random_shuffle(q+l,q+(r+ysuperman)/2);
		}
		int u=q[l++];
		vis[u]=0;
		for(int i=head[u];i;i=g[i].nxt){tmer++;
			int v=g[i].v,w=g[i].w;
			if(dis[u]+w<dis[v]){
				dis[v]=dis[u]+w;
				in[v]=in[u]+1;
				if(in[v]>n) return 1;
				if(!vis[v]){
				    if(l>1)q[--l]=v;
					else q[++r]=v;
					vis[v]=1;
				}
			} 
		}
	}
	return 0;
}

int s,k;
signed main(){
	srand(time(NULL));
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>k; 
    for (int i = 1, x, a, b; i <= k; i++) {
        cin>>x>>a>>b;
        if (x == 1) {
            add(a, b, 0);
            add(b, a, 0);
        }
        if (x == 2) add(a, b, -1),kkk--;
        if (x == 3) add(b, a, 0);
        if (x == 4) add(b, a, -1),kkk--;
        if (x == 5) add(a, b, 0);
    }
    for (int i = 1; i <= n; i++) add(0, i, -1);
	if(SPFA(0)){
		cout<<-1;
		return 0;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		ans+=dis[i];
	cout<<-ans;
}  
posted @   exut  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
Title
点击右上角即可分享
微信分享提示