zoukankan      html  css  js  c++  java
  • ☆ [POJ1021] Intervals 「差分约束」

    传送门 >Here<

    题意:给出N段区间,并告诉你每段区间里有几个数(一个位置只能放一个数) 问总共至少有几个数

    解题思路

      差分约束题,本蒟蒻也是第一次做差分约束题……

      所谓差分约束,常常是通过最短路(或最长路)来解决一些约束问题,例如不等式组

      举个例子:$$x1 -x2 leq a1 (1)$$$$x2 -x3 leq a2 (2)$$$$x1 -x3 leq a3 (3)$$求解$x1-x3$的解集

      则我们可以让1~2连一条长度为a1的有向边,2~3连一条长度为a2的有向边,1~3连一条长度为a3的有向边

      我们会发现$(1)+(2)$可以得到$x1 - x3 leq a1 + a2$(利用了不等式之间相加的定理),因此得到一组不等式组$$x1 - x3 leq a1 + a2$$$$x1 -x3 leq a3 (3)$$

      而最终由于是小于等于的约数,解集应当取$Min{ a1+a2, a3 }$

      为什么可以转化为最短路问题呢?考虑一条路径,对于所有非起点且非终点的点,与其相邻的路径上的两个点对应了两条路径,不妨设为$a-s,s-b$,则当这两个不等式相加时,中介点$s$一定会被消掉。宏观来看,一条路径上所有非起点终点的点都将为被抵消掉。因此最后只剩下路径的头尾了。而要求解集,如果是$<$,则应该取最小值,也就是最短路了。

      以上是差分约束的基本概念。那么回到这道题来,好像和差分约束没什么关系?

      光看好像是没什么关系。由于是考虑区间内数的个数,不妨设想有一个前缀和数组s,这样$[a_i, b_i]$至少有$c_i$个元素就可以表示成$s[b_i] - s[a_i-1] >= c[i]$,我们会得到若干个这样的不等式,就可以做差分约束了——然而值得注意的是,刚才的例子里是小于等于,而这里是大于等于。所以这里的解集应当取到最大,所以求的是最长路而不是最短路

      真的仅仅只是这样吗?我们忽略了题目给的一个条件——每个位置只能放一个数,所以我们的约束条件少了,要加上对于每一个位置i,$s[i]-s[i-1] geq 0, s[i]-s[i-1] leq 1$(其实$s[i]-s[i-1]$)就是i这个位置的数的个数,不是0就是1. 对于小于等于的情况,同时乘以-1转换成大于等于的形式,$s[i-1]-s[i] geq -1$即可

    code

      注意Dijkstra是不能做负权的(有$s[i-1]-s[i] geq -1$的存在),所以用SPFA

    /*By QiXingzhi*/
    #include <cstdio>
    #include <cstring>
    #include <queue> 
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 500010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
        return x * w;
    }
    int N,L,R;
    int a,b,c,d[MAXN],vis[MAXN];
    int first[MAXN*2],nxt[MAXN*2],to[MAXN*2],cost[MAXN*2],num_edge;
    queue <int> q;
    inline void add(int u, int v, int w){
    //    printf("%d->%d  (%d)
    ", u,v,w);
        to[++num_edge] = v;
        cost[num_edge] = w;
        nxt[num_edge] = first[u];
        first[u] = num_edge;
    }
    inline void SPFA(int s){
        for(int i = 0; i <= N; ++i) d[i] = -INF;
        d[s] = 0;
        q.push(s);
        int u, v;
        while(!q.empty()){
            u = q.front();
            q.pop();
            vis[u] = 0;
            for(int i = first[u]; i; i = nxt[i]){
                v = to[i];
                if(d[u] + cost[i] > d[v]){
                    d[v] = d[u] + cost[i];
                    if(!vis[v]){
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    inline void Init(){
        memset(vis,0,sizeof(vis));
        memset(first,0,sizeof(first));
        memset(nxt,0,sizeof(nxt));
        memset(to,0,sizeof(to));
        memset(cost,0,sizeof(cost));
    }
    int main(){
    //    freopen(".in","r",stdin);
        while(scanf("%d",&N) == 1){
            L = N+1, R = -1;
            Init();
            for(int i = 1; i <= N; ++i){
                a=r,b=r,c=r;
                add(a, b+1, c);
                L = Min(L, a);
                R = Max(R, b+1);
            }
            for(int i = 2; i <= R; ++i){
                add(i+1, i, -1);
                add(i, i+1, 0);
            }
            SPFA(L);
        //    printf("R+1 = %d  L+1 = %d
    ",R+1,L+1);
            printf("%d
    ", d[R]);    
        }
        return 0;
    }
  • 相关阅读:
    Git批量删除的方法
    第五课 森さんは 七時に 起きます
    第一课 李さんは  中国人です
    如何设置上传文件控件 input type="file" 的 默认值
    如何用程序提交一个上传文件的请求
    MVC Beta 做的网站实践总结(上)
    泛型单一模式
    提高web站点性能的最佳实践
    扩展GridView实现的一个自定义无刷新分页,排序,支持多种数据源的控件TwfGridView
    [导入]将字符串中连续的空格转换为一个空格
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9396653.html
Copyright © 2011-2022 走看看