POJ-1201 Intervals---差分约束
題目鏈接:
https://vjudge.net/problem/POJ-1201
題目大意:
一個整數(shù)集合Z有n個區(qū)間,每個區(qū)間有3個值,ai,bi,ci代表,在區(qū)間[ai,bi]上至少有ci個整數(shù)屬于集合Z,ci可以在區(qū)間內(nèi)任意取不重復的點。
現(xiàn)在要滿足所有區(qū)間的約束條件,問最少可選多少個點。
Sample Input
5 3 7 3 8 10 3 6 8 1 1 3 1 10 11 1Sample Output
6思路:
求最小的整數(shù)集合Z滿足| Z ∩ [ ai,? bi ] | >= ci。意思就是在區(qū)間[ai,bi]上至少有ci個整數(shù)屬于集合Z。
可以建模成一個差分約束系統(tǒng)。以輸入的測試數(shù)據(jù)為例進行分析:
設S[i]是集合Z中小于等于i的元素個數(shù)。那么就有以下不等式組:
(1)Z集合中范圍在[ai, bi]的整數(shù)個數(shù)至少為ci,也就相當于S[bi] - S[ai - 1] >= ci
根據(jù)差分約束系統(tǒng)中的三角不等式(d[v] - d[u] <=? Edge[u][v])
上述不等式可以轉(zhuǎn)化成S[ai - 1] - S[bi] <= -ci ? ?? 邊:<bi, ai-1> 權(quán)值-ci
? ? 上述例子就有以下不等式組(1)
S2 - S7 <= -3
S7 - S10 <= -3
S5 - S8 <= -1
S0 - S3 <= -1
S9 - S11 <= -1
(2)根據(jù)實際情況,還有兩個約束條件
S[i] - S[i - 1] <= 1
S[i] - S[i - 1] >= 0,即S[i - 1] - S[i] <= 0
?
最終要求的是什么?
設所有區(qū)間右端點的最大值為mx,如該測試數(shù)據(jù)中mx = 11, 所有區(qū)間左端點的最小值為mn
如該測試數(shù)據(jù)中mn = 1, mn - 1 = 0
最終要求的是S[mx] - S[mn - 1]的最小值,也就是S[mx] - S[mn - 1] >= M(M的最大值)
也就是S[mn - 1] - S[mx] <= -M(-M的最小值), 也就是點mx到點mn-1的最短路-M,答案求的是M
這里需要注意的是源點是mx,終點是mn-1。
所以進行bellman算法時,應該從mx出發(fā),求出dist[mn - 1]。(dist數(shù)組保存的是從源點出發(fā)到各點的最短距離)
?
?
但是上述的約束條件太多,最多會達到3*50000條邊,全部轉(zhuǎn)化成邊不是個好方法,所以應該進行優(yōu)化:
?
(1)用上述不等式組(1)進行建圖,源點到各個頂點最短路徑初始為0,因為Si - Smx <=0,所以源點到各個頂點的距離一定會小于等于0,
(2)用Bellman算法求出源點到各個頂點的最短路徑長度,每次循環(huán)時,判斷完約束條件(1)后,再判斷約束條件(2)和(3)
?
約束條件(2)的判斷
S[i] - S[i - 1] <= 1等效于S[i] - S[mx] <= S[i - 1] - S[mx] + 1
由于上述dist數(shù)組表示從源點出發(fā)到各點的最短距離,所以S[i] - S[mx]就是dist[i]
上述條件轉(zhuǎn)化成了dist[i] <= dist[i - 1] + 1
如果dist[i] > dist[i - 1] + 1, 那么修改dist[i] = dist[i - 1] + 1。
約束條件(3)的判斷
S[i - 1] <= S[i] 等效于S[i - 1] - S[mx] <= S[i] - S[mx]?
也就是dist[i - 1] <= dist[i]
如果dist[i - 1] > dist[i] 那就修改dist[i- 1] = dist[i]
?
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #include<stack> 8 #include<map> 9 #include<set> 10 #include<sstream> 11 #define MEM(a, b) memset(a, b, sizeof(a)); 12 using namespace std; 13 typedef long long ll; 14 const int maxn = 50000 + 10; 15 const int INF = 0x3f3f3f3f; 16 int T, n, m, cases, tot; 17 int d[maxn]; 18 struct edge 19 { 20 int u, v, w; 21 edge(){} 22 edge(int u, int v, int w):u(u), v(v), w(w){} 23 }; 24 edge a[maxn]; 25 int mx, mn;//mn左區(qū)間最小值,mx右區(qū)間最大值 26 void init() 27 { 28 tot = 0; 29 MEM(d, 0)//初始化源點0到各個頂點的距離,這里的d[mx]永遠是0,這就是源點 30 mx = 1, mn = INF; 31 } 32 void bellman() 33 { 34 bool update = 1; 35 while(update)//如果有不更新的時候,直接退出 36 { 37 update = 0; 38 for(int i = 0; i < n; i++)//Bellman算法的邊循環(huán) 39 { 40 int u = a[i].u, v = a[i].v, w = a[i].w; 41 if(d[v] > d[u] + w) 42 { 43 update = 1; 44 d[v] = d[u] + w; 45 } 46 } 47 48 //約束條件2的判斷 49 for(int i = mn; i <= mx; i++) 50 { 51 if(d[i] > d[i - 1] + 1) 52 { 53 update = 1; 54 d[i] = d[i - 1] + 1; 55 } 56 } 57 58 //約束條件3的判斷 59 for(int i = mx; i >= mn; i--) 60 { 61 if(d[i - 1] > d[i]) 62 { 63 update = 1; 64 d[i - 1] = d[i]; 65 } 66 } 67 } 68 } 69 int main() 70 { 71 while(cin >> n) 72 { 73 init(); 74 int u, v, w; 75 for(int i = 0; i < n; i++) 76 { 77 scanf("%d%d%d", &u, &v, &w); 78 a[i] = edge(v, u - 1, -w);//建邊 79 mx = max(mx, v); 80 mn = min(mn, u); 81 } 82 //cout<<mx<<" "<<mn<<endl; 83 bellman(); 84 printf("%d\n", -d[mn - 1]); 85 } 86 return 0; 87 }?
轉(zhuǎn)載于:https://www.cnblogs.com/fzl194/p/8734451.html
總結(jié)
以上是生活随笔為你收集整理的POJ-1201 Intervals---差分约束的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HBase在大搜车金融业务中的应用实践
- 下一篇: 第215天:Angular---指令