1. 程式人生 > >POJ 1201 Intervals - 差分約束

POJ 1201 Intervals - 差分約束

() ont tin -a mes int lose 技術分享 onclick

description

有$n$個區間 $[a_i, b_i]$, 以及$c_i$, 有一個整數集合Z, 要求對於每個區間$[a_i, b_i] 中的數不少於$c_i$個。

Solution

設$s_k$ 表示前k個數至少要選幾個, 顯然有$s[b_i] - s[a_i - 1] >= c_i$, 然後就是一個很顯然的差分約束

另外還需滿足: $s_{k+1} - s_k >= 0$, $s_{k+1} - s_k <= 1$

所以從$a_i - 1$ 向 $b_i$連一條長度為$c_i$的邊

從$k$向$k+1$連長度為$0$ 的邊

從$k+1$向$k$連長度為$-1$的邊

跑一遍最長路即可求出答案

Code

技術分享圖片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #define rd read()
 6 #define rep(i,a,b) for(int i = (a); i <= (b); ++i)
 7 #define per(i,a,b) for(int i = (a); i >= (b); --i)
 8 using namespace std;
9 10 const int N = 5e5 + 1e4; 11 const int M = 3e6; 12 const int inf = ~0U >> 2; 13 14 int n, dis[N], vis[N], cnt[N]; 15 int tot, head[N]; 16 17 queue<int> q; 18 19 struct edge { 20 int nxt, to, val; 21 }e[M]; 22 23 int read() { 24 int X = 0, p = 1; char c = getchar();
25 for(; c > 9 || c < 0; c = getchar()) if(c == -) p = -1; 26 for(; c >= 0 && c <= 9; c = getchar()) X = X * 10 + c - 0; 27 return X * p; 28 } 29 30 void add(int u, int v, int val) { 31 e[++tot].to = v; 32 e[tot].val = val; 33 e[tot].nxt = head[u]; 34 head[u] = tot; 35 } 36 37 int spfa() { 38 q.push(0); 39 dis[0] = 0; 40 for(int u; !q.empty();) { 41 u = q.front(); q.pop(); 42 vis[u] = 0; 43 for(int i = head[u]; i; i = e[i].nxt) { 44 int nt = e[i].to; 45 if(dis[nt] >= dis[u] + e[i].val) continue; 46 dis[nt] = dis[u] + e[i].val; 47 if(!vis[nt]) vis[nt] = 1, q.push(nt); 48 } 49 } 50 return dis[(int)5e5 + 1]; 51 } 52 53 int main() 54 { 55 n = rd; 56 for(int i = 0; i <= 5e5; ++i) { 57 add(i, i + 1, 0); add(i + 1, i, -1); 58 } 59 memset(dis, -1, sizeof(dis)); 60 rep(i, 1, n) { 61 int a = rd, b = rd, c = rd; 62 add(a, b + 1, c); 63 } 64 printf("%d\n", spfa()); 65 }
View Code

POJ 1201 Intervals - 差分約束