做网络流时发现的奇怪现象
查看原帖
做网络流时发现的奇怪现象
292064
xkai楼主2022/4/15 15:56

这份代码的建图方式可以通过本题,但若采用注释中的建图方式就会 TLE。生成了几组数据后发现是 spfa 之后的增广路成环了,导致 EK 的时候死循环(奇怪的是明明有环 spfa 却没死)。

两种建图方式我认为没有本质区别,只是把图倒过来而已。求问造成这种现象的原因。

#include<bits/stdc++.h>
using namespace std;
const double INF=1e6,eps=1e-8;
const int P=100010,E=1000010;
int S,T,head[P],ver[E],ne[E],edge[E],idx=2;double cost[E];
void add(int x,int y,int z,double c){
	ver[idx]=y,edge[idx]=z,cost[idx]=c,ne[idx]=head[x],head[x]=idx++;
	ver[idx]=x,edge[idx]=0,cost[idx]=-c,ne[idx]=head[y],head[y]=idx++;
}
queue<int>q;
bool vis[P];
int now[P],pre[P],fl[P];double dis[P];
bool spfa(){
	for(int i=1;i<=T;i++)dis[i]=INF;
	memcpy(now,head,sizeof now);
	q.push(S);dis[S]=0,pre[S]=0;
	while(q.size()){
		int x=q.front();q.pop();
//		cerr<<"VIS"<<x<<'\n';
		vis[x]=0;
		for(int i=head[x];i;i=ne[i])
			if(edge[i]&&dis[x]+cost[i]<dis[ver[i]]){
				dis[ver[i]]=dis[x]+cost[i];
				fl[ver[i]]=min(fl[x],edge[i]);
				pre[ver[i]]=i;
				if(!vis[ver[i]])vis[ver[i]]=1,q.push(ver[i]);
			}
	}
	return dis[T]!=INF;
}
double res;
int EK(){
	fl[S]=0x3f3f3f3f;
	if(!spfa())return false;
	int x=T,flow=fl[T];
	while(x!=S){
		res+=flow*cost[pre[x]];
		edge[pre[x]]-=flow,edge[pre[x]^1]+=flow;
		x=ver[pre[x]^1];
//		cerr<<x<<'\n';
	}
	return flow;
}
int n;
struct Point{
	int x,y;
}p[410];
double Dis(Point&a,Point&b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>p[i].x>>p[i].y;
	S=3*n+1,T=S+1;
	for(int i=1;i<=n;i++){
//		add(S,i,1,0);		
//		for(int j=1;j<=n;j++)
//			if(p[j].y>p[i].y){
//				add(i,j+n,1,Dis(p[i],p[j]));
//			}
//		add(i+n,T,2,0);
		add(S,i,2,0);
		for(int j=1;j<=n;j++)
			if(p[j].y<p[i].y){
				add(i,j+n,1,Dis(p[i],p[j]));
			}
		add(i+n,T,1,0);
	}
	int tmp,flow=0;
	while((tmp=EK()))flow+=tmp;
	if(flow!=n-1)cout<<"-1\n";
	else cout<<fixed<<setprecision(15)<<res;
}

附一个数据生成器:

#include<bits/stdc++.h>
using namespace std;
mt19937 rd(chrono::high_resolution_clock().now().time_since_epoch().count());
int random(int x){
	return rd()%x;
}
int main(){
	freopen("data.in","w",stdout);
	int n=400;
	cout<<n<<'\n';
	for(int i=1;i<=n;i++){
		cout<<random(2001)-1000<<' '<<random(2001)-1000<<'\n';
	}
}
2022/4/15 15:56
加载中...