POJ 1201 Intervals 题解 (差分约束系统)

题意:

给定n个闭合的整数区间 [ai, bi] ,以及对应的n个整数 c1, ..., cn 。现在要你求一个整数集合 Z ,使得对于每一个整数区间 [aibi],该整数集合 Z 至少包括有 c个位于于区间 [ai, bi] 的整数。问该整数集合 Z 最少要包括几个数。

分析:

假设 d[ s ] 表示从 0 到 s 共有 d[ s ] 个数位于集合 Z 中,其中 d[ -1 ] = 0 。那么对于区间 [ai, bi] 以及对应的整数 ci ,应满足 d[ b] - d[ a- 1 ] >= ci 。又由于对于区间 [i-1, i] 之间只有两个数字 i-1 i ,因此有 0 <= d[ i ] - d[ i - 1] <= 1 。所以由以上可以得出三条不等式:

1. d[ b] - d[ a- 1 ] >= ci

2. d[ i ] - d[ i - 1] <= 1

3. d[ i ] - d[ i - 1] >= 0

对其进行适当变换,可得到:

1. d[ a- 1 ] - d[ b] <= -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+1a 的边,其权值为 -c 。最后我们用SPFA算法求 Max+10 的最短路径。

代码:

#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;
}
View Code

 

posted on 2018-01-22 22:02  tobyn  阅读(216)  评论(0)    收藏  举报

导航