差分約束模板

2022-05-01 23:54:10 字數 2757 閱讀 2361

如果乙個系統由 $n$ 個變數和 $m$ 個約束條件組成,其中每個約束條件形如 $x_i - x_j <= c_k$,其中 $c_k$ 是常數(可以是負數,也可以是非負數),則稱其為差分約束系統。我們要解決的問題是:求一組解 $x_1= a-1, x_2 = a_2,...,x_n = a_n$,使得所有的約束條件得到滿足,否則判斷無解。

差分約束系統中的每個約束條件 $x_i - x_j \leq  c_k$ 都可以變形成 $x_i  \leq  c_k + x_j$,這與單源最短路中的三角形不等式 $dis[y] \leq dis[x] + w$ 非常相似。因此,我們可以把每個變數 $x_i$ 看作圖中的乙個節點,對於每個約束條件 $x_i - x_j \leq c_k$,從節點 $j 向節點 $i 連一條長度為 $c_k$ 的有向邊。

注意到,如果 $\$是該差分約束系統的一組解,那麼對於任意的常數 $d$,$\$ 顯然也是該差分約束系統的一組解。

設 $dis[0]=0$ 並向每個點連一條邊,跑單源最短路演算法。若圖中存在負環,則給定的差分約束系統無解,否則,$x_i = dis[i]$ 為該差分約束系統的一組解。

一般使用 $belllman-ford$ 或佇列優化的 $bellman-ford$ (俗稱 $spfa$)判斷圖中是否存在負環,最壞的時間複雜度為 $o(nm)$.

洛谷 p1993 小k的農場

求解差分約束系統,有 $m$ 條約束條件,每條形如 $x_a-x_b\geq c_k$,$x_a - x_b \leq c_k$,或 $x_a=x_b$ 的形式,判斷該差分系統有沒有解。

對於 $x_a = x_b$ 可以拆成等價的 $x_a \leq x_b$ 和 $x_a \geq x_b$.

建圖,然後跑單源最短路判斷是否存在負環即可。

bellman-ford版很慢,用時11.77s

#includeusing

namespace

std;

typedef

long

long

ll;const ll inf = 1ll << 61

;const

int maxv = 4*10000 + 10; //

最大頂點數

const

int maxe = 4*10000 + 10; //

最大邊數

//至少3倍空間

ll dis[maxv];

struct

edge

edge[maxe];

inttot;

intn, m;

void addedge(int u, int v, int

w)bool bellman_ford(int

s)

for (int i = 0; i < tot; i++)

if (dis[edge[i].v] > dis[edge[i].u] +edge[i].w)

return

false

;

return

true;}

intmain()

else

if(order == 2

)

else

}for(int i = 1;i <= n;i++) addedge(0, i, 0); //

保證圖的聯通,權值隨便

n++; //

增加源點0

if(bellman_ford(0)) printf("

yes\n");

else printf("

no\n");

//for(int i = 1;i < n;i++) printf("%d: %d\n", i, dis[i]); 可以輸出一組解

return0;

}

view code

dfs-spfa版的,很適合用來判斷負環,0 ms(雖然時間複雜度極度不穩定)

#include const

int maxn = 1e4+4

;const

int inf = 0x7fffffff

;int

n, m;

struct

ee[maxn

<<3

];int

head[maxn], en;

void add(int u, int v, int

w)int

vis[maxn], dis[maxn], spfa_flag;

void spfa(int

u) dis[v] = dis[u] +e[i].w;

spfa(v);}}

vis[u] = 0;}

intop, a, b, c;

intmain()

if(op==1

)

if(op==2

) }

//for(int i = 1; i <= n; i++) add(n+1, i, 0);

for(int i = 1; i <= n; i++) dis[i] = 0

;

for(int i = 1; i <= n; i++) if (!vis[i]) spfa(i);

if(spfa_flag) printf("

no\n");

else printf("

yes\n");

return0;

}

view code

1. 2. 

差分約束 模板

如果需要求的是兩個變數差的最大值,那麼需要將所有不等式轉變成 leq 的形式,建圖後求最短路 如果需要求的是兩個變數差的最小值,那麼需要將所有不等式轉化成 geq 的形式,建圖後求最長路。這是兩個最基本的規則 算是吧 差分約束的精髓就在於建圖,而這玩意兒個人感覺沒什麼好辦法,只能靠不停做題去找到那種...

差分約束及其模板

關於差分約束,演算法導論 講的挺明白的了。有一點要注意的是x1 x2 w在圖上對應的是x2 x1的邊權為w的一條邊,而不是x1 x2,這一點不要搞糊塗了。以下是我的差分約束的模板,解決的是 演算法導論 上的例子 include include include using namespace std ...

差分約束系統 模板

差分約束系統 如果乙個系統由n個變數和m個約束條件組成,其中每個約束條件形如 xj xi bk i j 1,n k 1,m 則稱其為差分約束系統。例如如下的約束條件 x1 x2 0 x1 x5 1 x2 x5 1 x3 x1 5 x4 x1 4 x4 x3 1 x5 x3 3 x5 x4 3 全都是...