zoukankan      html  css  js  c++  java
  • poj 1201 差分约束

    http://www.cnblogs.com/wangfang20/p/3196858.html

    题意:

    求集合Z中至少要包含多少个元素才能是每个区间[ai,bi]中的元素与Z中的元素重合个数为ci。

    思路:对于dis[b]-dis[a]>=c的形式,我们建一条a到b的边,权值为c,最后求最长路就是要得到的最小值。

    可举一例,[1,8]假使有7个不同的数,[1,4]假使有2个不同的数,[4,8]假使有3个不同的数,都满足f[8]-f[1]>=7,f[4]-f[1]>=2,f[8]-f[4]>=3.若求最短路,那么肯定得到的结果是5,与f[8]-f[1]>=7相矛盾。故求得是最长路,得到7就是最小的结果。

    可是紧紧这样建边,并不能将每个离散的点整合到一个图中,对于任何一个单元区间,1=>f[i+1]-f[i]>=0,故我们就可以得到两个式子f[i+1]-f[i]>=0与f[i]-f[i+1]>=-1;

    最后根据式子建边,求差分约束。

    要注意的是要将右边界+1,。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define inf 1<<30
    #define Maxn 51000
    #define Maxm 500000
    using namespace std;
    int dis[Maxn],vi[Maxn],minn,maxn,index[Maxn],e,Que[1000010];
    struct Edge{
        int to,next,val;
    }edge[Maxm];
    void init()
    {
        for(int i=0;i<=Maxn-1;i++)
            dis[i]=-inf;
        memset(vi,0,sizeof(vi));
        memset(index,-1,sizeof(index));
        e=maxn=0;
        minn=inf;
    }
    void addedge(int from,int to,int val)
    {
        edge[e].to=to;
        edge[e].val=val;
        edge[e].next=index[from];
        index[from]=e++;
    }
    int spfa()
    {
        int i,j,temp,head,rear;
        head=rear=0;
        Que[head++]=minn;
        dis[minn]=0;
        //cout<<maxn<<endl;
        while(head!=rear)
        {
            temp=Que[rear++];
            //cout<<temp<<endl;
            vi[temp]=0;
            for(i=index[temp];i!=-1;i=edge[i].next)
            {
                int now=edge[i].to;
                if(dis[now]<dis[temp]+edge[i].val)
                {    dis[now]=dis[temp]+edge[i].val;
                    if(!vi[now])
                        Que[head++]=now;
                    vi[now]=1;
                }
            }
        }
        return dis[maxn];
    }
    int main()
    {
        int i,j,n,a,b,c;
        while(scanf("%d",&n)!=EOF)
        {
            init();
            //cout<<"ok"<<endl;
            for(i=1;i<=n;i++)
            {
                scanf("%d%d%d",&a,&b,&c);
                b++;
                minn=min(minn,a);
                maxn=max(maxn,b);
                addedge(a,b,c);
            }
            for(i=minn;i<maxn;i++)
            {
                addedge(i,i+1,0);
                addedge(i+1,i,-1);
            }
            printf("%d
    ",spfa());
        }
        return 0;
    }
  • 相关阅读:
    搭建DG(data guard),及搭建过程中遇到的一些小问题 高伟
    介绍linux下vi命令的使用
    linux gcc编译器使用
    Linux进程编程介绍
    事件与接口实例讲解 C#
    Linux 2.6内核的编译步骤及模块的动态加载
    C# 各种定时器比较 zz
    linux下增加系统调用
    VirtualBox共享文件夹
    C++程序的单元测试(转贴)
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3196858.html
Copyright © 2011-2022 走看看