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

    这里简要记一下差分约束。

    所谓差分约束,指的是由a-b>=c这种不等式组组成的约束系统。一般的线性规划问题可以用单纯形法解决,但是这种特殊情况可以借助最短路算法解决。

    记源点到v的最短路为d[v],从u到v的最短路为d(u,v)。差分约束的最短路做法基于最短路的以下特点:

    对于没有负圈的图,任意两点d[u]+d(u,v)>=d[v],实际上相当于一条从u到v的长度为d的边(类比求最短路的过程,可以知道的d[v]的最终值是(d[u]+d(u,v))的最小值)。

    对于约束条件都转化成以上形式连边之后,所求得的d[t]-d[s]也就是d[t]其实就是原约束条件下d[t]-d[s]的最大值。(因为各路径的约束条件中取等号即最短路时差取最大值d(u,v))

    对于求最小值的情况,需要转化成d[u]+d(u,v)<=d[v]这样的形式,然后连边求最长路,与最短路时对称。

    1201代码:

    #include<iostream>
    #include<map>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<functional>
    #include<set>
    #define pb push_back
    #define fs first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    const int maxv=5e4+400;
    struct E{
        int t,w;
        E *next;
    }es[maxv*4];
    int h=0;
    E *G[maxv];
    E *tail[maxv];
    void add(int from,int to,int w){
        tail[from]->next=&es[h++];
        tail[from]->t=to;
        tail[from]->w=w;
        tail[from]=tail[from]->next;
        tail[from]->next=NULL;
    }
    int n;
    int dis[maxv];
    int s=maxv,t=0;
    bool vis[maxv];
    queue<int> Q;
    void BF(int s){
        for(int i=s;i<=t;i++) dis[i]=-1e9;
        dis[s]=0;
        Q.push(s);
        vis[s]=1;
        while(!Q.empty()){
            int v=Q.front();
            Q.pop();
            vis[v]=0;
            for(E *i=G[v];i->next!=NULL;i=i->next){
                E &e=*i;
                if(dis[e.t]<dis[v]+e.w){
                    dis[e.t]=dis[v]+e.w;
                    if(!vis[e.t]){
                        vis[e.t]=1;
                        Q.push(e.t);
                    }
                }
            }
        }
        cout<<dis[t]<<endl;
    }
    int main(){
        //////freopen("/home/files/CppFiles/in","r",stdin);
        cin>>n;
        for(int i=0;i<maxv;i++){
             G[i]=&es[h++];
             tail[i]=G[i];
             tail[i]->next=NULL;
        }
        for(int i=0;i<n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);////左闭右开区间
            s=min(s,x);
            t=max(t,y+1);
            add(x,y+1,z);
        }
        for(int i=0;i<maxv-1;i++){
            add(i,i+1,0);
            add(i+1,i,-1);
        }
        BF(s);
        return 0;
    }
    View Code

    PS:这题卡vector邻接表。。。。

  • 相关阅读:
    php获取文件后缀名格式
    猴子分桃问题2
    猴子吃桃问题1
    判断字符串中字母出现的次数用分割法
    成绩表
    二维数组所有元素求和输出
    冒泡排序
    1.8作业
    1.8
    1.6
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4652955.html
Copyright © 2011-2022 走看看