一、差分約束系統是啥?
差分約束系統(system of difference constraints),是求解關於一組變數的特殊不等式組之方法。如果乙個系統由n個變數和m個約束條件組成,其中每個約束條件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),則稱其為差分約束系統(system of difference constraints)。亦即,差分約束系統是求解關於一組變數的特殊不等式組的方法。
通俗一點地說,差分約束系統就是一些不等式的組,而我們的目標是通過給定的約束不等式組求出最大值或者最小值或者差分約束系統是否有解。
在這裡插入描述
二、差分約束系統求解
差分約束系統可以轉化為圖論來解決,對應於上面的不等式組,如果要求出x3-x0的最大值的話,疊加不等式可以推導出x3-x0<=7,最大值即為7,我們可以通過建立乙個圖,包含6個頂點,對每個xj-xi<=bk,建立一條i到j的有向邊,權值為bk。通過求出這個圖的x0到x3的最短路可以知道也為7,這是巧合嗎?並不是。
之所以差分約束系統可以通過圖論的最短路來解,是因為xj-xi<=bk,會發現它類似最短路中的三角不等式d[v] <=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。而求取最大值的過程類似於最短路演算法中的鬆弛過程。
三、差分約束的應用以及變形
差分約束系統的應用很廣,都會有一定的背景,我們只需要根據題意構造出差分約束系統,然後再根據題目的要求求解就行了。
一般題目會有三種情況:(1)、求取最短路 (2)、求取最長路 (3)、判斷差分約束系統的解是否存在
當然這三種也可能會相互結合
差分約束系統的解法如下:
1、 根據條件把題意通過變數組表達出來得到不等式組,注意要發掘出隱含的不等式,比如說前後兩個變數之間隱含的不等式關係。
2、 進行建圖:
首先根據題目的要求進行不等式組的標準化。
(1)、如果要求取最小值,那麼求出最長路,那麼將不等式全部化成xi – xj >= k的形式,這樣建立j->i的邊,權值為k的邊,如果不等式組中有xi – xj > k,因為一般題目都是對整形變數的約束,化為xi – xj >= k+1即可,如果xi – xj = k呢,那麼可以變為如下兩個:xi – xj >= k, xi – xj <= k,進一步變為xj – xi >= -k,建立兩條邊即可。
(2)、如果求取的是最大值,那麼求取最短路,將不等式全部化成xi – xj <= k的形式, 這樣建立j->i的邊,權值為k的邊,如果像上面的兩種情況,那麼同樣地標準化就行了。
(3)、如果要判斷差分約束系統是否存在解,一般都是判斷環,選擇求最短路或者最長路求解都行,只是不等式標準化時候不同,判環地話,用spfa即可,n個點中如果同乙個點入隊超過n次,那麼即存在環。
值得注意的一點是:建立的圖可能不聯通,我們只需要加入乙個超級源點,比如說求取最長路時圖不聯通的話,我們只需要加入乙個點s,對其他的每個點建立一條權值為0的邊圖就聯通了,然後從s點開始進行spfa判環。最短路類似。
3、 建好圖之後直接spfa或bellman-ford求解,不能用dijstra演算法,因為一般存在負邊,注意初始化的問題。
例題ccf-再賣菜
分析及思路:
這道題是非常經典的最短路解差分約束問題
如何建圖呢 ?
首先這裡的不等式是這樣的:
假設n=5,則有:
a1* 2≤ x1+x2 ≤ a1* 2+1
a2* 3≤ x1+x2+x3 ≤ a2* 3+2
a3* 3≤ x2+x3+x4 ≤ a3* 3+2
a4* 3≤ x3+x4+x5 ≤ a4* 3+2
a5* 2≤ x4+x5 ≤ a5* 2+1
x1≥1
x2≥1
x3≥1
x4≥1
x5≥112
3456
78910
xi為第一天第i家店的售價,ai為第二天第i家點的售價。
不難發現存在3元一次不等式怎麼辦呢?我們可以引入中間變數si=x0+x1+…+xi,這裡的x0等於0;
即可將上面的第乙個不等式轉化成: a1* 2≤ s2-s0 ,a1* 2+1≤s0-s2.其它的也一樣,不一一枚舉,全部轉化成大於等於的形式,sj-si≥k,i到j建立一條權值為k的單向邊,然後spfa跑最長路即可,這裡的spfa與原來的spfa有些區別,在spfa之前記得將所有點加入佇列,並且dist置0,因為差分約束系統不保證圖是連通的,所以要先建立乙個虛擬節點,這個虛擬節點為源點,向所有邊連線一條權值為0的有向邊,以上的操作便是人工省略了虛擬源點的步驟。
ac**:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 350;
struct node
node(int _v, int _val):v(_v),val(_val){}
};int n;
vector g[maxn];
int a[maxn],dis[maxn],vis[maxn],inq[maxn];
void spfa()
for(int i=0; ig[0].push_back(node(2,a[1]*2));
g[2].push_back(node(0,-(a[1]*2+1)));
g[n-2].push_back(node(n,a[n]*2));
g[n].push_back(node(n-2,-(a[n]*2+1)));
for(int i=1; i<=n; ++i) g[i-1].push_back(node(i,1));
memset(dis, 0, sizeof(dis));
memset(vis, 0, sizeof(vis));
memset(inq, 0, sizeof(inq));
spfa();
a[1] = dis[1];
for(int i=2; i<=n; ++i) a[i] = dis[i] - dis[i-1];
cout 本文參考 迷你之忍 的文章 ccf再賣菜 試題編號 201809 4 試題名稱 再賣菜 時間限制 1.0s 記憶體限制 256.0mb 問題描述 在一條街上有n個賣菜的商店,按1至n的順序排成一排,這些商店都賣一種蔬菜。第一天,每個商店都自己定了乙個正整數的 店主們希望自己的菜價和其他商店的一致,第... ccf csp首頁 以下都是我自己做過的題目,答案也全是自己做的,和網上大牛的最優解還是有差距。試題編號 試題名稱 最高得分 201912 1 報數100 201912 2 站選址 100201909 1 小明種蘋果 100201909 2 小明種蘋果 續 100201909 3 字元畫201903... 試題編號 201703 2 試題名稱 學生排隊 時間限制 1.0s 記憶體限制 256.0mb 問題描述 體育老師小明要將自己班上的學生按順序排隊。他首先讓學生按學號從小到大的順序排成一排,學號小的排在前面,然後進行多次調整。一次調整小明可能讓一位同學出隊,向前或者向後移動一段距離後再插入佇列。例如...CCF CSP201809 4再賣菜(記憶化搜尋)
CCF CSP題目彙總
ccf csp 題目 學生排隊