差分約束系統

2021-09-26 04:43:00 字數 2763 閱讀 5855

演算法簡介

差分約束系統是一種特殊的n元一次不等式組,它包含n個變數x1−

xn

x_1 - x_n

x1​−xn

​以及m個約束條件,每個約束條件都是由兩個變數作差構成的,形如xi−

xj

<=c

kx_i - x_j <= c_k

xi​−xj

​<=c

k​,其中c

kc_k

ck​是常數(可以為負),1<= i , j <= n, 1 <= k <= m。我們要解決的問題是:求一組解,x1=

a1,x

2=a2

,...

,xn=

an

x_1 = a_1, x_2 = a_2 ,... , x_n = a_n

x1​=a1

​,x2

​=a2

​,..

.,xn

​=an

​使得所有約束條件都得到滿足。

差分約束系統的每個約束條件xi−

xj

<=c

kx_i - x_j <= c_k

xi​−xj

​<=c

k​可以變形為x

i<=x

j+ck

x_i <= x_j + c_k

xi​<=x

j​+c

k​,這與單源最短路中的三角不等式 dis[ y ] <= dis[ x ] + z非常類似,因此可以把每個變數x_i 看作有向圖中的乙個節點 i ,對於每個約束條件xi−

xj

<=c

kx_i - x_j <= c_k

xi​−xj

​<=c

k​, 從節點j 向節點 i 連一條長度為 c

kc_k

ck​ 的有向邊。

注意到如果集合a是一組解,那麼a+d也是一組解(作差後d被消掉)。

設dis[0] = 0,以0為起點求單源最短路,若圖中存在負環則差分約束系統無解。否則,xi=

dis[

i]

x_i = dis[i]

xi​=di

s[i]

就是差分約束系統的一組解。

在某些題目中,xi−

xj

>=c

kx_i - x_j >= c_k

xi​−xj

​>=c

k​,仍可以看作是從 j 到 i 連成長度為 c

kc_k

ck​的有向邊,只是改為計算單源最長路徑,若圖中存在正環則無解。當然也可以不等式兩邊同時取負,使得變換成標準形式。

結論差分約束是基於三角不等式的乙個推廣。關鍵在於根據題意構造出恰當的狀態,建立狀態間的不等關係,並證明滿足不等式的乙個解與原問題一一對應,然後便可以利用spfa演算法求解。其優點是不等式關係明顯,易於理解,缺點是適用性窄。

例題模板

zju1420 出納員問題

題意簡述:

有一家24小時營業的超市,需要僱傭一批出納員。一天中每個小時需要出納員的最少數量為r0,r1,r2,…,r23。有n個人申請這項工作,每個申請者,從乙個特定時刻ti,開始連續工作恰好8個小時。(ti為整數,且0<=ti<=23 )。你的任務是計算出需要僱傭出納員的最少數目,滿足在每一時刻k,至少有ri名出納員在工作。

解題思路:

真的有點難想啊,首先我們要假設num[i] 為 i 時刻能夠開始工作的人數,x[i] 為實際僱傭人數,那麼x[i] <= num[i] 。而r[i]是i 時刻至少需要的人數,這由題目給出。

我們令s[i] = x[i] + x[i-1] + … + x[1] ,顯然我們就會得到關於 s 和 num 的一組不等式,如果想要答案正確,需要找到所有隱含的條件:

s[i] - s[i-1] >= 0 //(0 <= i <= 23)

s[i-1] - s[i] >= -num[i] // (0<=i<=23)

s[i] - s[i-8] >= r[i] //(8<=i<=23)

s[i] - s[i+16] >= r[i] - s[23] // (0 <= i <= 7)

注意到,s[23]本是未知數,但是我們將它作為常數處理,具體做法是我們遍歷s[23]的所有可能的值,並依次進行一次spfa,嘗試找尋僱傭最小人數 且使得不等式組成立的可能。 注意如果 i 從0開始,那麼鄰接表存有向圖,head節點就不能初始化為0,防止死迴圈超時。

**示例:

#include#include#include#includeusing namespace std;

int t,n,r[30],num[30];

const int n = 1e5+10;

const int inf = 0x3f3f3f3f;

int head[n],ver[n],edge[n],nex[n],tot;

int dis[100],vis[100],ts[100];

void addedge(int x,int y,int z)

queueq;

bool spfa(int s)

//printf("%d %d %d\n",x,y,dis[x]);}}

return dis[24] == s;

}bool solve(int z)

int main()

if(flag) puts("no solution");

}return 0;

}

參考資料

差分約束系統

差分約束 若 s a s b k 建一條b到a 的長度為k的邊 若s a s b k 建一條b到a 的長度為 k的邊 是求最小值的最長路 是求最大值的最短路 注意到最短路演算法的鬆弛操作 if d j d i w i j d j d i w i j 這其中的三角形不等式 d j d i w i j ...

差分約束系統

差分約束系統 對於差分不等式,a b c 建一條 b 到 a 的權值為 c 的邊,求的是最短路,得到的是最大值 對於不等式 a b c 建一條 b 到 a 的權值為 c 的邊,求的是最長路,得到的是最小值 存在負環的話是無解 求不出最短路 dist 沒有得到更新 的話是任意解 第三 一種建圖方法 設...

差分約束系統

差分約束系統 x1 x2 0 x1 x5 1 x2 x5 1 x3 x1 5 x4 x1 4 x4 x3 1 x5 x3 3 x5 x4 3 不等式組 1 全都是兩個未知數的差小於等於某個常數 大於等於也可以,因為左右乘以 1就可以化成小於等於 這樣的不等式組就稱作差分約束系統。這個不等式組要麼無解...