查分约束系统

来源:互联网 发布:linux删除一个目录 编辑:程序博客网 时间:2024/04/28 20:57

查分约束系统

定义

如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法.

观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。

例如,考虑这样一个问题,寻找一个5维向量x=(xi)以满足:
这一问题等价于找出未知量xi,i=1,2,…,5,满足下列8个差分约束条件:

x1-x20x1-x5-1x2-x51x3-x15x4-x14x4-x3-1x5-x3-3x5-x4-3

该问题的一个解为x=(-5,-3,0,-1,-4),另一个解y=(0,2,5,4,1),这2个解是有联系的:y中的每个元素比x中相应的元素大5。

引理:设x=(x1,x2,…,xn)是差分约束系统Ax≤b的一个解,d为任意常数。则x+d=(x1+d,x2+d,…,xn+d)也是该系统Ax≤b的一个解。

算法核心思路,寻找约束关系,差分约束小于等于最短路,大于等于最长路.用spfa或者bellman_ford算法求解

队列优化的spfa算法

void spfa(int start,int n){    int top = 0;    for(int v = 1;v<=n;v++){        if(v==start){            Q[top++] = v;            vis[v] = true;            d[v] = 0;        } else{            vis[v] = false;            d[v] = inf;        }    }    while (top!=0){        int u = Q[--top];        vis[u] = false;        for(int i = head[u];i!=-1;i=es[i].next){            int v = es[i].to;            if(d[v]>d[u]+es[i].cost){                d[v] = d[u]+es[i].cost;                if(!vis[v]){                    vis[v] = true;                    Q[top++] = v;                }            }        }    }}

bellman_ford算法

struct Edge{    int from;    int to;    int cost;}es[max_v];void addEdge(int a,int b,int c){    es[tol].from = a;    es[tol].to = b;    es[tol].cost = c;    tol++;}void shortest_path(int s){    for(int i = 0;i<=n;i++){        d[i] = inf;    }    d[s] = 0;    int times = 0;    bool update = true;    while (times<n&&update){        update = false;        for(int i = 0;i<m;i++){            Edge now = es[i];            if(d[now.from]!=inf&&d[now.to]>d[now.from]+now.cost){                d[now.to] = d[now.from]+now.cost;                //cout<<now.to<<" "<<d[now.to]<<endl;                update = true;            }        }        times++;    }    /*if(d[n]==inf){        cout<<-2<<endl;        return;    }    if(times==n){        cout<<-1<<endl;    } else{        cout<<d[n]<<endl;    }*/}

poj1201 Intervals (最长路)

题目链接 poj1201

//// Created by 王若璇 on 16/6/1.//#include <iostream>#include <cstring>#include <cstdio>#include <queue>#include <algorithm>using namespace std;const int max_n = 200500;const int inf = 0x3f3f3f3f; //差分约束小于等于最短路,大于等于最长路.int head[max_n];int d[max_n];struct Edge{    int to;    int cost;    int next;}es[max_n];int tol = 0;int up = 0;int down = 0x3f3f3f3f;queue<int> qu;bool vis[max_n];int n;void addEdge(int a,int b,int c){    es[tol].to = b;    es[tol].cost = c;    es[tol].next = head[a];    head[a] = tol++;}void spfa(int s,int t){    for(int i = down;i<=up;i++){        d[i] = -inf;    }    while (!qu.empty()){        qu.pop();    }    qu.push(s);    d[s] = 0;    vis[s] = true;    while (!qu.empty()){        int u = qu.front();        qu.pop();        vis[u] = false;        for(int i = head[u];i!=-1;i = es[i].next){            int v = es[i].to;            if(d[v]<d[u]+es[i].cost){                d[v] = d[u]+es[i].cost;                if(!vis[v]){                    vis[v] = true;                    qu.push(v);                }            }        }    }}int main(){    ios::sync_with_stdio(false);    cin.tie(NULL);    while (cin>>n){        memset(head,-1, sizeof(head));        for(int i = 0;i<n;i++){            int a,b,c;            cin>>a>>b>>c;            addEdge(a-1,b,c);            up = max(up,b);            down = min(down,a-1);        }        for(int i = down;i<up;i++){            addEdge(i,i+1,0);            addEdge(i+1,i,-1);        }        spfa(down,up);        cout<<d[up]-d[down]<<endl;    }    return 0;}

poj3159 (最短路)

题目链接 poj3159

//// Created by 王若璇 on 16/5/31.//#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <queue>#include <vector>using namespace std;const int max_n = 30030;const int max_v = 150000;const int inf = 0x3f3f3f3f;int d[max_n];//int c[max_n][max_n];int n,m;int head[max_n];bool vis[max_n];int Q[max_n];struct Edge{    int to;    int cost;    int next;};Edge es[max_v];int tol;void add(int a,int b,int v){    es[tol].to = b;    es[tol].cost = v;    es[tol].next = head[a];    head[a] = tol++;}void spfa(int start,int n){    int top = 0;    for(int v = 1;v<=n;v++){        if(v==start){            Q[top++] = v;            vis[v] = true;            d[v] = 0;        } else{            vis[v] = false;            d[v] = inf;        }    }    while (top!=0){        int u = Q[--top];        vis[u] = false;        for(int i = head[u];i!=-1;i=es[i].next){            int v = es[i].to;            if(d[v]>d[u]+es[i].cost){                d[v] = d[u]+es[i].cost;                if(!vis[v]){                    vis[v] = true;                    Q[top++] = v;                }            }        }    }}int main(){    //ios::sync_with_stdio(false);    //cin.tie(NULL);    while (scanf("%d%d",&n,&m)!=EOF){        //memset(vis,0, sizeof(vis));        memset(head,-1,sizeof(head));        tol = 0;        while (m--){            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add(a,b,c);        }        spfa(1,n);        //cout<<d[n]<<endl;        printf("%d\n",d[n]);        //cout<<dijstra(1,n)<<endl;    }    return 0;}
0 0
原创粉丝点击