(非标算)注意Floyd判负环WA#12
查看原帖
(非标算)注意Floyd判负环WA#12
149877
Austin_Xu_楼主2024/7/1 11:25

邻接矩阵版的Floyd,初始化

#define INF 0x3FFFFFFF
...
int d[MAXN][MAXN];
void init()
{
	...
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		{
			d[i][j]=INF;
		}
	}
	for(int i=1;i<=n;++i)
	{
		d[i][i]=0;
	}
	...
}

输入数据后,正常地跑Floyd

void solve()
{
	for(int k=1;k<=n;++k)
	{
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)
			{
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
			}
		}
	}
	...
}

最后出答案

void solve1()
{
	...
	for(int i=1;i<=n;++i)
	{
		if(d[i][i]<0&&d[1][i]!=INF)
		{
			cout<<"YES"<<endl;
			return;
		}
	}
	cout<<"NO"<<endl;
	return;
}

结果是WA#12。

哪里出错了呢?考虑这组数据:

1
3 2
2 3 -1
3 2 -1

显然地,在2->3->2存在负环,而1到2、3均无边,应输出NO。

然而按我这么写,输出结果会是YES。

让我们看向万恶之源:

d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

d[1][2]和d[1][3]均为INF,然而d[2][3]为-1!

当外层k循环跑到2时,对经过2的路径进行松弛,使得d[1][3]被松弛为INF-1。这意味着,带负权边时,两个不可及的点经Floyd松弛后的距离可能不为INF。即不应使用d[i][j]!=INF来判断不存在从i到j的路径。

现在来解决这个问题。

#define inf 0x1FFFFFFF
...
void solve1()
{
	...
	for(int i=1;i<=n;++i)
	{
		if(d[i][i]<0&&d[1][i]<inf)
		{
			...
		}
	}
	...
}

使用inf作为判断是否可达的边界。如果不可达,初值为INF的距离经过若干次松弛,应当大于等于inf。

这里的inf是随便设的。直觉上,如果INF可以作为极大,其一半也就可以作为极小。(考虑到不开辅助数组的2维Floyd可能在一轮松弛中反复计算某条负权边,如果可以被卡掉当我没说)

喜提60(?)。标算还得是SPFA。

2024/7/1 11:25
加载中...