• 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.一般情况,题目会存在一些隐含的限制条件,需要我们推理出来

  • 相关阅读:
    172. Factorial Trailing Zeroes
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    91. Decode Ways
    LeetCode 328 奇偶链表
    LeetCode 72 编辑距离
    LeetCode 226 翻转二叉树
    LeetCode 79单词搜索
    LeetCode 198 打家劫舍
    LeetCode 504 七进制数
  • 原文地址:https://www.cnblogs.com/carcar/p/9673631.html
Copyright © 2020-2023  润新知