C++ 差分约束系统

最近开始学差分约束系统了,讲课时检验学习程度的一个好方法,于是我就在博客园试图讲一讲。

首先,我们要知道差分约束系统是什么:

如果一个不等式组由n个变量和m个约束条件形成,形成m个如a-b<=c(c是常数)的不等式,我们就称他为差分约束系统。

说简单点,差分约束系统就是求解一组符合不等式组的变量。

差分约束系统可以用图论算法中的最长路解。这次我们用SPFA。

我们知道了差分约束系统可以用最短路来解,那么就需要建图,建好图跑最短路就可以了,但问题是怎么建图呢?

要解决一个问题,可以举一些例子来帮助斯烤。我就来举一个a-b<=c的例子。

虽然这样子我们还是不知道怎么建图,但我们可以通过转化来把他转化成已知的知识,这样就可以知道如何建图。

我们可以把a-b<=c转化成a<=b+c,是不是,这样转化完,我们可以发现他和最短路的一个性质好像哦。就是zd(i)<=zd(j)+lj(i,j),嗯……用能看的懂的话翻译一下就是,一个点的最短路径,肯定小于等于另一个点的最短路径+过来的长度。届时,我们把a<=b+c代入一下,就可以知道如何建图了,那就是从b到a之间连接一个长度为c的路径。

那如果出现a-b>=c这种情况呢?不要慌,我们可以利用数学上学过的定律(具体那个我忘了),我们可以把>=两边的数都*-1,这个式子就会由a-b>=c变成b-a<=-c。然后我们就会做了。是不是很简单!

如果出现a-b=0这种情况直接都连就好了。

在跑之前,还要创造一个超级节点,来维持图的联通性。这样一来,整个图就建好了,我们只要跑一遍SPFA就可以得到想要的结果了。

好了讲完了。

哦哦还有代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<long long>p;
long long n,m,a,b,c,bj[5005],sz[5005],cs[5005],wz;
long long ans,head[5005];
struct hehe
{
	long long w,cd,syg;
}lsqxx[10005];//边最多是10000条(应该) 
void add(long long t,long long w,long long cd)//神奇又好用的链式前向星 
{
	ans++;
	lsqxx[ans].w=w;//结尾处 
	lsqxx[ans].cd=cd;//这条边的权值 
	lsqxx[ans].syg=head[t];//上一个起点是t的线的编号 
	head[t]=ans;//现在这个就是下一个的上一个(啊好乱) 
}
bool qg()
{
	for(int i=1;i<=n;i++)
	{
		sz[i]=1000;//求最短路当然先初始化 
	}
	while(p.empty()==false)
	{
		wz=p.front();
		bj[wz]=0;//现在他出去了 
		p.pop();
		for(int i=head[wz];i!=0;i=lsqxx[i].syg)
		{
			if(sz[lsqxx[i].w]>sz[wz]+lsqxx[i].cd)//松弛操作
			{
				sz[lsqxx[i].w]=sz[wz]+lsqxx[i].cd; 
				if(bj[lsqxx[i].w]==0)//如果已经在队列里面了,再加进去就是浪费时间了 
				{
					bj[lsqxx[i].w]=1; 
					cs[lsqxx[i].w]++;//进队列的次数增加了 
					if(cs[lsqxx[i].w]==n)//在SPFA中,一个点进入队列n次就一定有负环 
					{
						return false;
					}
					p.push(lsqxx[i].w);
				}
			}
		}
	}
	return true;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)//0号点是超级原点 
	{
		add(0,i,0);
	}
	for(int i=0;i<m;i++) 
	{
		cin>>a>>b>>c;//输入条件 
		add(b,a,c);//根据条件建图 
	}
	p.push(0);
	if(qg()==false)//有负环,没有解的 
	{
		cout<<"NO"<<endl;
	}else
	{
		for(int i=1;i<=n;i++)//sz[i]是最短路,这是一种可行情况 
		{
			cout<<sz[i]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/lichangjian/p/13399664.html