POJ 1201 Intervals 题解 (差分约束系统)
题意:
给定n个闭合的整数区间 [ai, bi] ,以及对应的n个整数 c1, ..., cn 。现在要你求一个整数集合 Z ,使得对于每一个整数区间 [ai, bi],该整数集合 Z 至少包括有 ci 个位于于区间 [ai, bi] 的整数。问该整数集合 Z 最少要包括几个数。
分析:
假设 d[ s ] 表示从 0 到 s 共有 d[ s ] 个数位于集合 Z 中,其中 d[ -1 ] = 0 。那么对于区间 [ai, bi] 以及对应的整数 ci ,应满足 d[ bi ] - d[ ai - 1 ] >= ci 。又由于对于区间 [i-1, i] 之间只有两个数字 i-1 和 i ,因此有 0 <= d[ i ] - d[ i - 1] <= 1 。所以由以上可以得出三条不等式:
1. d[ bi ] - d[ ai - 1 ] >= ci
2. d[ i ] - d[ i - 1] <= 1
3. d[ i ] - d[ i - 1] >= 0
对其进行适当变换,可得到:
1. d[ ai - 1 ] - d[ bi ] <= -ci
2. d[ i ] - d[ i - 1] <= 1
3. d[ i - 1] - d[ i ] <= 0
假设区间 [a1, b1] c1、[a2, b2] c2、[a3, b3] c3 ...... [an, bn] cn 中集合最大的上界为 Max,那么对于这道题,我们的目标是求得结果 d[ Max ] 的最小值。假设 d[ Max ] 的最小值为 T ,那么我们要求的结果可以用不等式 d[ Max ] - d[ -1 ] >= T。也就是 d[ -1 ] - d[ Max ] <= -T。可以发现这道题就是属于差分约束类型的题目。由于数组中没有对应于 -1 的下标,我们让每个数在数轴的对应位置上都向右移一位。整理以上不等式,可得:
1. d[ ai ] - d[ bi + 1 ] <= -ci
2. d[ i + 1 ] - d[ i ] <= 1
3. d[ i ] - d[ i + 1 ] <= 0
目标:d[ 0 ] - d[ Max + 1] <= -T(其中 d[ 0 ] = 0)
对于每一组区间 [ a, b ] 以及对应整数 c ,我们建立一条 b+1 到 a 的边,其权值为 -c 。最后我们用SPFA算法求 Max+1 到 0 的最短路径。
代码:
#include<cstdio> #include<algorithm> #include<queue> #define N 50050 #define INF 1e6 using namespace std; struct edge { int u, v, w, next; }es[N+1000000]; int head[N], d[N], ecnt; int n, Max; queue<int> q; void init() { ecnt = 0; Max = -INF; for(int i = 0; i < N; i++) { head[i] = -1; } } void add(int u, int v, int w) { es[ecnt].u = u; es[ecnt].v = v; es[ecnt].w = w; es[ecnt].next = head[u]; head[u] = ecnt++; } void spfa() { bool inq[N]; for(int i = 0; i <= Max; i++) { inq[i] = false; d[i] = INF; } d[Max] = 0; d[0] = 0; q.push(Max); inq[Max] = true; //这里没有写判断有无负环,看题目应该是没有负环的 while(!q.empty()) { int s = q.front(); q.pop(); inq[s] = false; for(int i = head[s]; i != -1; i = es[i].next) { int v = es[i].v; if(d[v] > d[s] + es[i].w) { d[v] = d[s] + es[i].w; if(!inq[v]) { q.push(v); inq[v] = true; } } } } } void solve() { spfa(); printf("%d\n", -d[0]); } int main() { int a, b, c; scanf("%d", &n); init(); for(int i = 0; i < n; i++) { scanf("%d %d %d", &a, &b, &c); add(b+1, a, -c); if(Max < b+1) { Max = b+1; } } for(int i = 0; i < Max; i++) { add(i, i+1, 1); add(i+1, i, 0); } solve(); return 0; }
浙公网安备 33010602011771号