如何卡SPFA

由于一个校内最短路题数据太水,于是就和司机一起研究如何卡SPFA...

正权边卡SPFA的基本思路是弄一个网格图,然后这个网格图行比列小得多,比如10*10000之类的...

然后对于竖着的边边权就设多么小,然后横着的边权就设多么大(比如1和rand()%10000+10)

还可以在图里随机加一些奇怪的边.

然后对于点个数1e5,边个数2e5的有向图,随机打乱边或随机打乱边+SLF的SPFA都被卡到了入队1e8次...


PS:

可以将横着的边权构造一下,说不定就可以卡得更大了...

发现随机边权模数不一样差别很大.

另外还有说什么把网格图搞成立方体图不知道会怎么样(因为升了一维嘛...)


代码可以参考一下:这份代码至少可以卡到入队8e7以上


#include<bits/stdc++.h>
using namespace std;
struct edge{int u,v,w;};
vector<edge>v;
int id[5000][5000],n=9,tp,m=42866/n,a[1000000];
int r(){
	return rand();
	//return rand()<<13|rand();
}
int main(){
	freopen("in.txt","w",stdout);
	srand(time(0));
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			id[i][j]=++tp,a[tp]=tp;
//	random_shuffle(a+1,a+tp+1);
	int SIZE=29989;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j){
			if(i<n){
				v.push_back(edge{id[i][j],id[i+1][j],1});
				v.push_back(edge{id[i+1][j],id[i][j],1});
				if(j<m){
					if(1)v.push_back(edge{id[i][j],id[i+1][j+1],r()%SIZE+10});
					else v.push_back(edge{id[i+1][j+1],id[i][j],r()%SIZE+10});
				}
			}
			if(j<m){
				v.push_back(edge{id[i][j],id[i][j+1],r()%SIZE+10});
				v.push_back(edge{id[i][j+1],id[i][j],r()%SIZE+10});
			}
		}
	fprintf(stderr,"[%d,%d,%d]",v.size(),n,m);
	random_shuffle(v.begin(),v.end());
//	printf("%d %d %d\n",tp,v.size(),2);
	printf("%d %d\n",tp,v.size());
	for(int i=0;i<v.size();++i)printf("%d %d %d\n",a[v[i].u],a[v[i].v],v[i].w);
//	for(int i=1;i<=10;++i)printf("%d ",a[id[1][10*i]]);
//	printf("%d %d",a[1],a[2]);
}



upd:发现一种奇妙的SPFA优化:每次将进队多次的点放到队首,可以过掉这种数据...


然而这个优化可以被一个最naive的数据卡掉...即

addedge(1,i,2*(n-i+1)+1),addedge(i,i-1,1),然后将这些边打乱后输出

这个也是最原始的卡SPFA方法,不加SLF的SPFA可以被这个卡掉


#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("spfa6.out","w",stdout);
	int n=99999,m=199996;
	printf("%d %d\n",n,m);
	for(int i=n;i>=2;--i)
		printf("1 %d %d\n%d %d 1\n",i,(n-i+1)*2+1,i,i-1);
}


  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值