zoukankan      html  css  js  c++  java
  • hdu1201,hdu6252差分约束系统

    差分约束系统一般用来解决a-b>=c的问题,有n个这样的限制条件,求出某个满足这些条件的解

    可以将这个问题转化成最长路问题,即b到a的距离最少为c,而有多条b到a的路的话,我们就取最长的b到a的距离。

    将限制条件转化成为一条边,然后求最长路,一般解决最长路问题,我们使用的算法是spfa

     入门题   hdu1201 

    题意:有n个限制条件,区间a到b至少是有c个点,求满足条件的最少端点数

    分析:需要满足所有条件,那么首先想到的是差分约束系统。先定义数组G,Gi为0到i有Gi个端点,那么条件a到b区间至少有c个端点可以转化成,Gb-G(a-1)>=c

    ,显然n个限制条件是不够的,还需要满足1>=G(i+1)-G(i)>=0,转化为,G(i+1)-G(i)>=0和G(i-1)-G(i)>=-1,用这些边构造一个图,然后G(max)即为答案

    由于边的数量比较多,用vector构图的话会超时,所以用邻接表加spfa

    ac代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxn = 50000+10;
    int f[maxn],nex[maxn*3],w[maxn*3],to[maxn*3],cnt;
    void add(int x,int y,int k)
    {
         cnt++;
         w[cnt]=k;
         to[cnt]=y;
         nex[cnt]=f[x];
         f[x]=cnt;
    }
    bool vis[maxn];
    int dis[maxn];
    
    int spaf()
    {
        for(int i=0;i<maxn;i++)dis[i]=-1;
        queue<int>que;
        que.push(0);
        vis[0]=1;
        dis[0]=0;
        while(que.size())
        {
          //  for(int i=0;i<=13;i++)cout<<dis[i]<<" ";cout<<endl;
    
            int x=que.front();
            que.pop();
            vis[x]=0;
           // cout<<x<<endl;
            for(int i=f[x];i;i=nex[i])
            {
               // cout<<to[i]<<" ";
                if(dis[x]+w[i]>dis[to[i]])
                {
                    dis[to[i]]=dis[x]+w[i];
                    if(vis[to[i]]==0)
                    {
                        vis[to[i]]=1;
                        que.push(to[i]);
                    }
                }
            }
          //  cout<<endl;
        }
    
    }
    int main()
    {
        int n;
        cin>>n;
        for(int i=0;i<maxn;i++)f[i]=0;
    
        for(int i=1;i<=n;i++)
        {
            int x,y,w;
            scanf("%d %d %d",&x,&y,&w);
            add(x,y+1,w);
        }
        for(int i=1;i<=50000+1;i++)
        {
            add(i-1,i,0);
            add(i,i-1,-1);
        }
        spaf();
        printf("%d
    ",dis[50000+1]);
    	return 0;
    }
    

      

    提升题    hdu6252

    题意:给出的也是限制条件,但是也需要注意一个限制条件,dis[i]-dis[i-1]>0

    ac代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxn=2005;
    int f[maxn],w[maxn*3],to[maxn*3],nex[maxn*3];
    bool vis[maxn];
    int out[maxn],cnt=0,dis[maxn],n,m,k;
    void add(int a,int b,int c)
    {
        cnt++;
        w[cnt]=c;
        to[cnt]=b;
        nex[cnt]=f[a];
        f[a]=cnt;
    }
    bool spfa()
    {
        for(int i=1; i<maxn; i++)dis[i]=-1,vis[i]=0,out[i]=0;
        queue<int>que;
        que.push(1);
        vis[1]=1;
        dis[1]=0;
        while(que.size())
        {
          //  for(int i=1;i<=n;i++)printf(" %d",dis[i]);cout<<endl;
            int x=que.front();
          //  cout<<x<<"out"<<endl;
            vis[x]=0;
            que.pop();
            out[x]++;
            if(out[x]>n)
                return false;
            for(int i=f[x]; i; i=nex[i])
            {
              //  cout<<to[i]<<"to"<<endl;
                if(dis[x]+w[i]>dis[to[i]])
                {
                    dis[to[i]]=dis[x]+w[i];
                    if(vis[to[i]]==0)
                    {
                        que.push(to[i]);
                        vis[to[i]]=1;
                    }
                }
            }
        }
        return true;
    }
    int main()
    {
        int T;
        cin>>T;
        for(int cn=1; cn<=T; cn++)
        {
            cnt=0;
            scanf("%d %d %d",&n,&m,&k);
            for(int i=1; i<maxn; i++)f[i]=0;
            for(int i=2; i<=n; i++)
                add(i-1,i,1);
            for(int i=1; i<=m; i++)
            {
                int a,b,c,d;
                scanf("%d %d %d %d",&a,&b,&c,&d);
                if(a==b&&c==d)
                {
                    add(b,c,k);
                    add(c,b,-k);
                }
                else
                {
                    add(c,b,1-k);
                    add(a,d,k+1);
                }
            }
            if(spfa())
            {
                printf("Case #%d:",cn);
                for(int i=2;i<=n;i++)
                    printf(" %d",dis[i]-dis[i-1]);
                cout<<endl;
            }
            else
                printf("Case #%d: IMPOSSIBLE
    ",cn);
        }
        return 0;
    }
    

    总结:

    1.如果给出的是a-b>c,我们可以转化为,a-b>=c+1

    2.如果给出的是a-b<=c,我们可以转化为,b-a>=-c

    3.对于a-b>=c,我们可以构成b到a距离为c的边,然后构成图,求最长路

    4.对于a-b<=c,我们可以构成b到a距离为c的边,然后构成图,求最短路

    5.如果这些限制条件存在矛盾,即没有合法的答案时,图会存在回路,只需要判断某个点出队次数超过n次,直接返回false

    6.一般情况,题目会存在一些隐含的限制条件,需要我们推理出来

  • 相关阅读:
    android 网络通信 okHttp
    android网络通信(1)
    Java 网络编程
    Android中实现TCP和UDP传输实例
    android保存图片到本地并可以在相册中显示出来
    [android]Android中图形图片及处理相关Api的小总结
    set android app lanuage programatically
    android怎么在不同环境设置下选择不同的resource呢
    MySQL修改root密码的多种方法
    Fragment 与Fragment沟通
  • 原文地址:https://www.cnblogs.com/carcar/p/9673631.html
Copyright © 2011-2022 走看看