ZOJ-1508 Intervals 差分约束

题意:给定若干个连续的整数区间[ai, bi]以及ci,现在要求这样一个集合Z,集合Z中的元素与每个给定的区间的元素交集至少有ci个。

解法:通过把dis[i]看做Z中小于等于整数i一共有多少个元素。那么对于题目给定条件有表达式dis[b] - dis[a-1] >= ci,根据这个不等式就能够进行构边了。除此之外,还有一些隐含的条件:0 <= dis[i]-dis[i-1] <= 1,对这些关系同样进行构边。然后要求的值就是dis[Max] - dis[Min-1] >= M中的M,其中Max和Min是出现的最小左、右边界,令dis[Max] = 0,那么就是求解的就是从Max到Min-1的最短路的相反数。

这里解释下为什么是从Max到Min-1的最短路,由于有dis[Max]-dis[Min-1]>=M恒成立时,而M同样是一个变量,因此要大于M就要大于M的最大值,因此问题转化为这个不等式中如何求解M的最大值,通过对式子的转化就为dis[Min-1]-dis[Max]<=-M,也就是求-M的最小值,而这个-M在途中最小就是Min-1到Max的最短路了,否则dis[Min-1]就会被dis[Max]-M代替了。

代码如下:

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int N, idx, head[50005];
int Min, Max;

// 设对图求出最短路表示的信息dis[i]表示Z集合中包含有多少个小于i的数 
struct Edge {
    int v, ct, next;
}e[160000];

void insert(int a, int b, int ct) {
    e[idx].v = b, e[idx].ct = ct;
    e[idx].next = head[a];
    head[a] = idx++;
}

int dis[50005];
char vis[50005];
#include <queue>

void spfa() {
    queue<int>q;
    memset(dis, 0x3f, sizeof (dis));
    memset(vis, 0, sizeof (vis));
    q.push(Max);
    vis[Max] = 1, dis[Max] = 0;
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        vis[v] = 0;
        int tv;
        for (int i = head[v]; i != -1; i = e[i].next) {
            if (dis[e[i].v] > dis[v] + e[i].ct) {
                dis[e[i].v] = dis[v] + e[i].ct;
                if (!vis[e[i].v]) {
                    q.push(e[i].v);
                    vis[e[i].v] = 1;    
                }
            }
        }
    }
}

int main() {
    int a, b, c;
    while (scanf("%d", &N) != EOF) {
        idx = 0;
        Min = 50005, Max = 0;
        memset(head, 0xff, sizeof (head));
        for (int i = 0; i < N; ++i) {
            scanf("%d %d %d", &a, &b, &c);
            ++a, ++b; // 由于0是有效的数字,因此待会最小数减1将会出现负数 
            Min = min(Min, a);
            Max = max(Max, b);
            insert(b, a-1, -c);
        }
        for (int i = Min; i <= Max; ++i) {
            insert(i-1, i, 1);
            insert(i, i-1, 0);
        }
        spfa();
        printf("%d\n", -dis[Min-1]);
    }
    return 0;    
}

 

posted @ 2013-03-13 15:30  沐阳  阅读(327)  评论(0编辑  收藏  举报