<更新提示>
<第一次更新>
<正文>
差分约束系统
我们先来认识一下差分约束系统鸭!
差分约束系统是一种特殊的\(n\)元一次不等式组,它包含了\(n\)个变量\(x_1-x_n\)以及\(m\)个不等式(约束条件)。其中每一个不等式形如\(x_i-x_j\leq c_k\),\(c_k\)是常数,\(i,j \leq n,k \leq m\)。
通常来说,题目会给出这一些限制条件的模型或变式,我们需要在满足这个不等式组的前提下求解一些指定的数值。
注意到不等式\(x_i-x_j\leq c_k\)我们可以将其转换为\(x_i\leq c_k+x_j\)。而最短路算法中的三角形不等式也是这个格式\(dis_j \leq dis_i+w\)(对于\(dis_j > dis_i+w\)我们需要更新最短路,故该式一定能得到满足),所以我们通常可以将差分约束系统的问题转化为最短路问题。一般地,我们将变量\(x_i,x_j\)看作图中的两个节点,而恰有一条长度为\(c_k\)的边从\(x_j\)连向\(x_i\)。这时候,边的含义是一个不等式。
更具体地来说,有一个很常见的问题。
对于给定的差分约束系统P,求\(\max\{x_n-x_1\}\)
先从代数角度思考,我们可以通过若干个不等式的相加得到如下的不等式组:
x_n-x_1\leq d_1
\\x_n-x_1\leq d_2
\\...
\\x_n-x_1\leq d_n
\end{cases}
\]
那么显然\(\min\{d_1,d_2,...,d_n\}\)就是答案。
从图论角度思考:先根据差分约束系统建图。
我们可以通过若干条边从不同的路径有节点1走到n。其中各个路径的权值和分别为\(d_1,d_2,...,d_n\),那么\(\min\{d_1,d_2,...,d_n\}\)是什么呢?
- 没错,最短路。
我们将一个差分约束系统的问题转换为了最短路问题。
接下来,我们通过一道入门例题来了解。
Candies(POJ3159)
Description
During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher brought the kids of flymouse’s class a large bag of candies and had flymouse distribute them. All the kids loved candies very much and often compared the numbers of candies they got with others. A kid A could had the idea that though it might be the case that another kid B was better than him in some aspect and therefore had a reason for deserving more candies than he did, he should never get a certain number of candies fewer than B did no matter how many candies he actually got, otherwise he would feel dissatisfied and go to the head-teacher to complain about flymouse’s biased distribution.
snoopy shared class with flymouse at that time. flymouse always compared the number of his candies with that of snoopy’s. He wanted to make the difference between the numbers as large as possible while keeping every kid satisfied. Now he had just got another bag of candies from the head-teacher, what was the largest difference he could make out of it?
Input Format
The input contains a single test cases. The test cases starts with a line with two integers N and M not exceeding 30 000 and 150 000 respectively. N is the number of kids in the class and the kids were numbered 1 through N. snoopy and flymouse were always numbered 1 and N. Then follow M lines each holding three integers A, B and c in order, meaning that kid A believed that kid B should never get over c candies more than he did.
Output Format
Output one line with only the largest difference desired. The difference is guaranteed to be finite.
Sample Input
2 2
1 2 5
2 1 4
Sample Output
5
解析
就是以上提到的差分约束系统。
题目大意:有\(n\)个孩子,\(m\)个要求,每一个要求形如:孩子\(a\)认为孩子\(b\)不能比他多超过\(c\)个糖果。求孩子\(1\)和孩子\(n\)最多相差的糖果数。
对于每一个要求,我们将其视为差分约束系统中的一个不等式即可。
\]
(节点a向节点b连一条权值为c的边)
建图后栈式\(SPFA\)(卡堆优化\(Dijkstra\)和队列\(SPFA\))跑最短路解决。
\(Code:\)
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int N=30000+80,M=150000+80;
struct edge{int ver,val,next;}e[M*4];
int n,m,Last[M],t,dis[N],vis[N];
inline void insert(int x,int y,int v)
{
e[++t].val=v;e[t].ver=y;
e[t].next=Last[x];Last[x]=t;
}
inline void input(void)
{
t=0;
memset(Last,0,sizeof Last);
for(int i=1;i<=m;i++)
{
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
insert(x,y,v);
}
}
inline void spfa(void)
{
memset(dis,0x7f,sizeof dis);
memset(vis,0x00,sizeof vis);
dis[1]=0;vis[1]=1;
stack< int > Stack;
Stack.push(1);
while(!Stack.empty())
{
int temp=Stack.top();
Stack.pop();
vis[temp]=0;
for(int i=Last[temp];i;i=e[i].next)
{
if(dis[e[i].ver]>dis[temp]+e[i].val)
{
dis[e[i].ver]=dis[temp]+e[i].val;
if(!vis[e[i].ver])
{
Stack.push(e[i].ver);
vis[e[i].ver]=true;
}
}
}
}
}
int main(void)
{
while(scanf("%d%d",&n,&m)==2)
{
input();
spfa();
printf("%d\n",dis[n]);
}
return 0;
}
<后记>