差分约束基本题型:

      给出一个序列,1至n这n个数字,然后已知从i 到j 的数字和至多a、至少b,给出这么一组,然后求每个数字最小为多少,或者求总和最小为多少。

      于是构造,设s[i]为0到i的和,那么s[1]即为第一个数字,s[2]-s[1]即为第二个数字,于是给出的条件转换为:

s[i] - s[j] >= b

s[i] - s[j] <= a

s[i] - s[i-1] >= 0

s[i] - s[i-1] <= V (*如果是1到n这n个容器,每个容器有容量,或者特殊情况n个布尔值,那么需要加上这个限制条件)

 

题目大意:

给出一些区间[ai,bi]和每个区间最少需要几个点ci,然后问总共最少需要几个点满足所有区间的要求。比如给出1 5 2 4 6 2,就是说15需要2个点,46需要2个点,那么最少需要2个点就可以满足条件了。

 

思路:

这个就是上面说的布尔值了,抽象成

s[bi] - s[ai-1] >= ci 

s[i] - s[i-1] >= 0 

 s[i] - s[i-1] <= 1

注意边界是s[bi]-s[ai-1],避免重复。

然后进行差分约束求最长路。另外,此题不需要判断是否不满足条件,即存在环。另外,全部初始化为0即可,或者除起始点为0其余点为-INF,然后松弛的时候判断一下。

PS:昨天去网上搜资料,打印资料,看了一天的差分约束,理解了大概思路,没实践。今天怀着忐忑的心情,建图,写SPFA,写完之后对比测试数据,一样。交第一遍,RE,立马将数组开到50010,第二遍,RE,想起昨天网上看的资料,一般数组大小都是4*SIZE左右,于是果断将数组开到200010,看Status,AC了。还得多写写差分约束的题。

有关差分约束的简单证明:http://hi.baidu.com/jffifa/item/ef628c50d37345dcd58bac44

差分约束求的是什么?http://whiteath.weebly.com/1/post/2010/11/2.html

ZOJ差分约束具体应用:http://whiteath.weebly.com/3/post/2010/12/zoj-150814551420.html

 

CODE:

 

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

const int SIZE = 50010;
const int INF = 0x3f3f3f3f;

int u[4*SIZE], v[4*SIZE], w[4*SIZE], next[4*SIZE];
int first[SIZE], d[SIZE];
int cnt, Min, Max;

void read_graph(int u1, int v1, int w1)
{
    u[cnt] = u1; v[cnt] = v1; w[cnt] = w1;
    next[cnt] = first[u[cnt]];
    first[u[cnt]] = cnt;
    cnt++;
}

void spfa(int src)
{
    queue<int> q;
    bool inq[SIZE] = {0};
    for(int i = Min; i <= Max; i++) d[i] = (i == Min)? 0:-INF;
    q.push(Min);
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        inq[x] = 0;
        for(int e = first[x]; e!=-1; e = next[e]) if(d[v[e]] < d[x]+w[e]) //最长路三角不等式
        {
           d[v[e]] = d[x] + w[e];
           if(!inq[v[e]])
           {
               inq[v[e]] = 1;
               q.push(v[e]);
           }
        }
    }
    printf("%d\n", d[Max]);
}

void init()
{
    memset(u, 0sizeof(u));
    memset(v, 0sizeof(v));
    memset(w, INF, sizeof(w));
    memset(first, -1sizeof(first));
    memset(next, 0sizeof(next));
    Min = INF;
    Max = 0;
}

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        init();
        cnt = 0;
        while(n--)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            x++; y++;
            Max = max(Max, y);
            Min = min(Min, x-1);
            read_graph(x-1, y, z);
        }
        for(int i = Min; i <= Max; i++)
        {
            read_graph(i-1, i, 0);
            read_graph(i, i-1, -1);
        }
        spfa(Min);
    }
}

 

posted on 2012-09-14 14:56  有间博客  阅读(545)  评论(0编辑  收藏  举报