zoukankan      html  css  js  c++  java
  • POJ 1201 & HDU1384 & ZOJ 1508 Intervals(差分约束+spfa 求最长路径)

    题目链接:

    POJ:http://poj.org/problem?id=1201

    HDU:http://acm.hdu.edu.cn/showproblem.php?

    pid=1384

    ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=508

    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 end points 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 <= 50000) -- 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 <= 50000 and 1 <= ci <= bi - ai+1.

    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

    Source



    题意:(转)

    [ai, bi]区间内和点集Z至少有ci个共同元素。那也就是说假设我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边。权值为ci,可是这远远不够。由于有非常多点依旧没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时。我们再看看Si的定义。也不难写出0<=Si - Si-1<=1的限制条件。尽管看上去是没有什么意义的条件,可是假设你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。

    我们将上面的限制条件写为允许的形式:

    Sbi - Sai >= ci

    Si - Si-1 >= 0

    Si-1 - Si >= -1

    这样一来就构造出了三种权值的边。而最短路自然也就没问题了。

    但要注意的是,因为查分约束系统里经常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。

    PS:

    由于求的是[ai,bi]区间,所以我们加入边的时候须要(u-1, v, w)!

    把距离dis初始化为负无穷, if(dis[v] < dis[u] + w)就可以!


    POJ 和ZOJ用队列和栈都能过,可是HDU用栈会超时,仅仅能用队列!

    代码例如以下:(栈)

    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define N 50017
    #define M 50017
    int n, m, k;
    int Edgehead[N], dis[N];
    struct Edge
    {
        int v,w,next;
    } Edge[3*M];
    bool vis[N];
    //int cont[N];
    int minn, maxx;
    int MIN(int a, int b)
    {
        if(a < b)
            return a;
        return b;
    }
    int MAX(int a, int b)
    {
        if(a > b)
            return a;
        return b;
    }
    void Addedge(int u, int v, int w)
    {
        Edge[k].next = Edgehead[u];
        Edge[k].w = w;
        Edge[k].v = v;
        Edgehead[u] = k++;
    }
    int SPFA( int start)//stack
    {
        int sta[N];
        int top = 0;
        //memset(cont,0,sizeof(cont);
        for(int i = 1 ; i <= n ; i++ )
            dis[i] = -INF;
        dis[start] = 0;
        //++cont[start];
        memset(vis,false,sizeof(vis));
        sta[++top] = start;
        vis[start] = true;
        while(top)
        {
            int u = sta[top--];
            vis[u] = false;
            for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意
            {
                int v = Edge[i].v;
                int w = Edge[i].w;
                if(dis[v] < dis[u] + w)
                {
                    dis[v] = dis[u]+w;
                    if( !vis[v] )//防止出现环
                    {
                        sta[++top] = v;
                        vis[v] = true;
                    }
                    //	if(++cont[v] > n)//有负环
                    //		return -1;
                }
            }
        }
        return dis[maxx];
    }
    int main()
    {
        int u, v, w;
        while(~scanf("%d",&n))//n为目的地
        {
            k = 1;
            memset(Edgehead,-1,sizeof(Edgehead));
            minn = INF;
            maxx = -1;
            for(int i = 1 ; i <= n ; i++ )
            {
                scanf("%d%d%d",&u,&v,&w);
                Addedge(u-1,v,w);
                maxx = MAX(v,maxx);
                minn = MIN(u-1,minn);
    
            }
            for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须加入每相邻两个整数点i,i+1的边
            {
                Addedge(i,i+1,0);
                Addedge(i+1,i,-1);
            }
            int ans = SPFA(minn);//从点minn開始寻找最短路
            printf("%d
    ",ans);
        }
        return 0;
    }


    HDU队列:

    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define N 50017
    #define M 50017
    int n, m, k;
    int Edgehead[N], dis[N];
    struct Edge
    {
        int v,w,next;
    } Edge[3*M];
    bool vis[N];
    //int cont[N];
    int minn, maxx;
    int MIN(int a, int b)
    {
        if(a < b)
            return a;
        return b;
    }
    int MAX(int a, int b)
    {
        if(a > b)
            return a;
        return b;
    }
    void Addedge(int u, int v, int w)
    {
        Edge[k].next = Edgehead[u];
        Edge[k].w = w;
        Edge[k].v = v;
        Edgehead[u] = k++;
    }
    int SPFA( int start)//stack
    {
        queue<int>q;
        //int sta[N];
        //memset(cont,0,sizeof(cont);
        int top = 0;
        for(int i = minn ; i <= maxx ; i++ )
            dis[i] = -INF;
        dis[start] = 0;
        //++cont[start];
        memset(vis,false,sizeof(vis));
        //sta[++top] = start;
        q.push(start);
        vis[start] = true;
        while(!q.empty())
        {
            //int u = sta[top--];
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意
            {
                int v = Edge[i].v;
                int w = Edge[i].w;
                if(dis[v] < dis[u] + w)
                {
                    dis[v] = dis[u]+w;
                    if( !vis[v] )//防止出现环
                    {
                        //sta[++top] = v;
                        q.push(v);
                        vis[v] = true;
                    }
                    //    if(++cont[v] > n)//有负环
                    //        return -1;
                }
            }
        }
        return dis[maxx];
    }
    int main()
    {
        int u, v, w;
        while(~scanf("%d",&n))//n为目的地
        {
    
            k = 1;
            memset(Edgehead,-1,sizeof(Edgehead));
            minn = INF;
            maxx = -1;
            for(int i = 1 ; i <= n ; i++ )
            {
                scanf("%d%d%d",&u,&v,&w);
                Addedge(u-1,v,w);
                maxx = MAX(v,maxx);
                minn = MIN(u-1,minn);
    
            }
            for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须加入每相邻两个整数点i,i+1的边
            {
                Addedge(i,i+1,0);
                Addedge(i+1,i,-1);
            }
            int ans = SPFA(minn);//从点minn開始寻找最短路
            printf("%d
    ",ans);
        }
        return 0;
    }
    

  • 相关阅读:
    一次偶然的Java内存溢出引发的思考
    centos6.4下面安装postgresql以及客户端远程连接
    用springMVC构建restful程序,接收以及返回json数据格式
    如何编译spring源码,并导入到eclipse中
    模仿MFC封装Windows API
    一些好用的控制台命令
    014:字符串:各种其奇葩的内置方法
    013:元组:戴上了枷锁的列表
    012:列表:一个打了激素的数组3
    011:列表:一个打了激素的数组2
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6991430.html
Copyright © 2011-2022 走看看