• POJ 1384 Intervals (区间差分约束,根据不等式建图,然后跑spfa)


    传送门:

    http://acm.hdu.edu.cn/showproblem.php?pid=1384

    Intervals

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 4841    Accepted Submission(s): 1815


    Problem Description
    You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.

    Write a program that:

    > reads the number of intervals, their endpoints and integers c1, ..., cn from the standard input,

    > computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i = 1, 2, ..., n,

    > writes the answer to the standard output
     
    Input
    The first line of the input contains an integer n (1 <= n <= 50 000) - the number of intervals. The following n lines describe the intervals. The i+1-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50 000 and 1 <= ci <= bi - ai + 1.

    Process to the end of file.

     
    Output
    The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i = 1, 2, ..., n.
     
    Sample Input
    5 3 7 3 8 10 3 6 8 1 1 3 1 10 11 1
     
    Sample Output
    6
     
    Author
    1384
     
    Recommend
    Eddy   |   We have carefully selected several similar problems for you:  1529 1531 1548 1534 1317 
    题目意思:
    给出 n 个区间,每个区间有个权值 Ci,最终找出一个最少的数字的集合,使得满足每个区间中至少包含 Ci 个数。
    给你几组的a,b,c
    从区间a到b(闭区间)选择至少c个数放入集合
    要求集合中的数字最少,问你最少多少个数字
     
    分析:
    f(a)表示从0到a有f(a)个数放入集合
    那么a,b,c根据不等式建立边
    f(b)-f(a-1)>=c
     
    这个不等式的意思是:从区间a,b里面选择至少c个数加入集合
    隐藏的不等式:0<=f(i)-f(i-1)<=1
     
    变形一下:
    f(i)-f(i-1)>=0
    f(i-1)-f(i)>=-1
     
    根据这三个不等式建立边
    找到区间在最左端:minn
    找到区间的最右端:maxx
    所以这样建立边的话,跑最短路的时候
    起点应该是max,终点是min-1
    f(max)-f(min-1)>=x
    x就是我们需要的结果
    code:
    #include <iostream>
    #include <cstdio>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #include<memory>
    #include<queue>
    #include<vector>
    using namespace std;
    #define max_v 50010
    #define INF 9999999
    int tot;
    int head[max_v];
    int vis[max_v];
    int dis[max_v];
    int minn,maxx;
    struct node
    {
        int u,v,val;
        int next;
    }Edge[max_v<<2];
    void addEdge(int u,int v,int val)
    {
        Edge[tot].u=u;
        Edge[tot].v=v;
        Edge[tot].val=val;
        Edge[tot].next=head[u];
        head[u]=tot++;
    }
    void spfa()
    {
        for(int i=minn-1;i<=maxx;i++)
            dis[i]=-INF;
        queue<int> q;
        dis[maxx]=0;
        vis[maxx]=1;
        q.push(maxx);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=Edge[i].next)
            {
                int v=Edge[i].v;
                if(dis[v]<dis[u]+Edge[i].val)
                {
                    dis[v]=dis[u]+Edge[i].val;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        printf("%d
    ",dis[minn-1]);
        return ;
    }
    int main()
    {
        int n,a,b,c;
        while(~scanf("%d",&n))
        {
            tot=0;
            memset(head,-1,sizeof(head));
            memset(vis,0,sizeof(vis));
            maxx=0;
            minn=INF;
            for(int i=0;i<n;i++)
            {
                scanf("%d %d %d",&a,&b,&c);
                a++;
                b++;
                minn=min(minn,a);
                maxx=max(maxx,b);
                addEdge(b,a-1,c);
            }
            for(int i=minn;i<=maxx;i++)
            {
                addEdge(i,i-1,0);
                addEdge(i-1,i,-1);
            }
            spfa();
        }
        return 0;
    }

    今天学差分约束的时候又遇到了这个题,跑最长路初始化的时候搞错了,应该是dis[i]=-INF。。。。,卡了好一会

    题目意思:
    从一系列区间[a,b]中每个至少取ci个数构成集合s,问你集合s至少需要多少个数
    区间约束问题,差分约束解决
    分析:
    f(x):[0,x]区间内取f(x)个数
    则区间[a,b]内至少取c个数可以变形为:f(b)-f(a-1)>=c
    隐藏关系:1>=f(i)-f(i-1)>=0,变形一下:
    f(i)-f(i-1)>=0
    f(i-1)-f(i)>=-1
    maxx:所有区间的最大值
    minx:所有区间的最小值
    i属于[minx,maxx]
    总结一下得到这样三个关系:
    f(b)-f(a-1)>=c
    f(i)-f(i-1)>=0  i属于[minx,maxx]
    f(i-1)-f(i)>=-1 i属于[minx,maxx]
    这三个表达式的形式都是一样的,xi-xj>=c
    按照j->i建边,权值为c
    所以:
    (a-1)->b 建边 权值c
    (i-1)->i 建边 权值0
    i->(i-1) 建边 权值-1
    我们要求的东西ans可以变形为:f(maxx)-f(minx-1)>=ans
    >=是最小值,所以是最长路
    所以是问你从minx-1到maxx的最长路
    建图完毕之后spfa跑一遍最长路,不能用dj,因为存在负权边
    code:
    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<string.h>
    #include<set>
    #include<map>
    #include<list>
    #include<math.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define INF 9999999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    
    int getval()
    {
        int ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    
    #define max_v 50005
    int dis[max_v];
    int vis[max_v];
    
    struct node
    {
        int v,w;
        node(int vv=0,int ww=0):v(vv),w(ww){}
    };
    vector<node> G[max_v];
    int n,m;
    
    void init()
    {
        for(int i=0;i<max_v;i++)
            G[i].clear();
        for(int i=0;i<max_v;i++)
        {
            dis[i]=-INF;
            vis[i]=0;
        }
    }
    
    void spfa(int s)
    {
    
        queue<int> q;
        q.push(s);
        vis[s]=1;
        dis[s]=0;
    
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=0;
    
            for(int j=0;j<G[u].size();j++)
            {
                int v=G[u][j].v;
                int w=G[u][j].w;
                if(dis[v]<dis[u]+w)//最长路
                {
                     dis[v]=dis[u]+w;
                     if(vis[v]==0)
                     {
                         vis[v]=1;
                         q.push(v);
                     }
                }
            }
        }
    }
    
    int f(int u,int v)
    {
       for(int j=0;j<G[u].size();j++)
       {
           if(G[u][j].v==v)
            return 0;
       }
       return 1;
    }
    int main()
    {
        int a;
        while(~scanf("%d",&a))
        {
            int x,y,w;
            init();
            int maxx=-INF,minx=INF;
            for(int i=1;i<=a;i++)
            {
                scanf("%d %d %d",&x,&y,&w);
                x++,y++;//防止减1的时候出现负数
                maxx=max(maxx,y);
                minx=min(minx,x);
                if(f(x-1,y))//预防重边
                    G[x-1].push_back(node(y,w));
            }
            for(int i=minx;i<=maxx;i++)
            {
                if(f(i-1,i))//预防重边
                    G[i-1].push_back(node(i,0));
                if(f(i,i-1))//预防重边
                    G[i].push_back(node(i-1,-1));
            }
            spfa(minx-1);
            printf("%d
    ",dis[maxx]);
        }
        return 0;
    }
    /*
    题目意思:
    从一系列区间[a,b]中每个至少取ci个数构成集合s,问你集合s至少需要多少个数
    区间约束问题,差分约束解决
    
    分析:
    f(x):[0,x]区间内取f(x)个数
    
    则区间[a,b]内至少取c个数可以变形为:f(b)-f(a-1)>=c
    隐藏关系:1>=f(i)-f(i-1)>=0,变形一下:
    f(i)-f(i-1)>=0
    f(i-1)-f(i)>=-1
    maxx:所有区间的最大值
    minx:所有区间的最小值
    
    i属于[minx,maxx]
    
    总结一下得到这样三个关系:
    f(b)-f(a-1)>=c
    f(i)-f(i-1)>=0  i属于[minx,maxx]
    f(i-1)-f(i)>=-1 i属于[minx,maxx] 
    
    这三个表达式的形式都是一样的,xi-xj>=c
    按照j->i建边,权值为c
    所以:
    (a-1)->b 建边 权值c
    (i-1)->i 建边 权值0
    i->(i-1) 建边 权值-1
    
    我们要求的东西ans可以变形为:f(maxx)-f(minx-1)>=ans
    >=是最小值,所以是最长路
    所以是问你从minx-1到maxx的最长路
    建图完毕之后spfa跑一遍最长路,不能用dj,因为存在负权边
    
    */
  • 相关阅读:
    C#LPT端口连接热敏打印机发送指令
    c# 普通打印机大致有三种方法(非热敏打印机及lpt1并口指令控制型)
    C#直接发送打印机命令到打印机(这里测试的是直接弹出钱箱操作)
    c#操作access,update语句不执行的解决办法
    element-ui dialog组件添加可拖拽位置 可拖拽宽高[转]
    [JavaScript] js实现简单的代码运行框【转】
    HTML5 drag & drop 拖拽与拖放简介[转]
    webpack 单独打包指定JS文件(转)
    跳转地图并定位
    基于Cesium实现逼真的水特效[转]
  • 原文地址:https://www.cnblogs.com/yinbiao/p/9445855.html
Copyright © 2020-2023  润新知