POJ1201Intervals(差分約束系統)


    昨天看了下差分約數系統的含義,其實就是如果有n個變量在m個形如aj-ai>=bk條件下,求解的此不等式的方法。

   而這種不等式的解法其實就是轉化為圖論的最小路的算法求解的。我們將上面的不等式邊形后得到aj>=ai+bk正好就可以看做是從ai到aj權值是bk的一條路徑最短的邊。這樣一來,只要依照題目的條件寫出一系列這樣的不等式,也就是相當於按照題意增加了一些合法的邊,也就完全轉化為了最短路的算法。

   再看這道題,題目說[ai, bi]區間內和點集Z至少有ci個共同元素,那也就是說如果我用Si表示區間[0,i]區間內至少有多少個元素的話,那么Sbi - Sai >= ci,這樣我們就構造出來了一系列邊,權值為ci,但是這遠遠不夠,因為有很多點依然沒有相連接起來(也就是從起點可能根本就還沒有到終點的路線),此時,我們再看看Si的定義,也不難寫出0<=Si - Si-1<=1的限制條件,雖然看上去是沒有什么意義的條件,但是如果你也把它構造出一系列的邊的話,這樣從起點到終點的最短路也就順理成章的出現了。

我們將上面的限制條件寫為同意的形式:

Sbi - Sai >= ci

Si - Si-1 >= 0

Si-1 - Si >= -1

這樣一來就構造出了三種權值的邊,而最短路自然也就沒問題了。

但要注意的是,由於查分約束系統里常常會有負權邊,所以為了避免負權回路,往往用Bellman-Ford或是SPFA求解(存在負權回路則最短路不存在)。

 1 #include <map>
 2 #include <set>
 3 #include <stack>
 4 #include <queue>
 5 #include <cmath>
 6 #include <ctime>
 7 #include <vector>
 8 #include <cstdio>
 9 #include <cctype>
10 #include <cstring>
11 #include <cstdlib>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 #define eps 1e-15
16 #define MAXN  50005
17 #define INF 1000000007
18 #define MAX(a,b) (a > b ? a : b)
19 #define MIN(a,b) (a < b ? a : b)
20 #define mem(a) memset(a,0,sizeof(a))
21 
22 struct EDGE//使用鄰接表存邊
23 {
24     int v;
25     int w;
26     int next;
27 }edge[3*MAXN];
28 int head[MAXN], d[MAXN], vis[MAXN],N, n, Max,Min;
29 
30 void AddEdge(int u,int v,int w)//添加新邊
31 {
32     edge[N].v = v;
33     edge[N].w = w;
34     edge[N].next = head[u];
35     head[u] = N++;
36 }
37 
38 void SPFA()//此題數據較大,用Bellman-ford恐怕過不了
39 {
40     for(int i=Min;i<=Max;i++) d[i] = -INF;
41     d[Min] = 0;
42     queue<int>q;
43     q.push(Min);
44     while(!q.empty())
45     {
46         int x = q.front(); q.pop();
47         vis[x] = 0;
48         for(int e=head[x];e != -1;e=edge[e].next)if(d[edge[e].v] < d[x] + edge[e].w)
49         {
50             d[edge[e].v] = d[x] +edge[e].w;
51             if(!vis[edge[e].v])
52             {
53                 q.push(edge[e].v);
54                 vis[edge[e].v] = 1;
55             }
56         }
57     }//由於題目說一定有解,我就略去了判斷是否存在負權回路
58 }
59 
60 int main()
61 {
62     while(~scanf("%d", &n))
63     {
64         int u,v,w; N = 0;
65         memset(head,-1,sizeof(head));
66         mem(vis);  mem(edge);
67         Min = INF;  Max = -INF;
68         for(int i=0;i<n;i++)
69         {
70             scanf("%d%d%d", &u,&v,&w);//題目條件的邊
71             AddEdge(u,v+1,w);
72             Min = MIN(Min, u);//在這里記錄最小值和最大值,所求的就是以Min為源點
73             Max = MAX(Max, v+1);//以Max為終點的最短路
74         }
75         for(int i = Min;i < Max; i++)//添加新邊
76         {
77             AddEdge(i,i+1,0);
78             AddEdge(i+1,i,-1);
79         }
80         SPFA();
81         printf("%d\n", d[Max]);
82     }
83     return 0;
84 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM