最短路径之差分约束

一、前言

本文的目的是探讨最短路径与差分约束之间的关系。为了方便理解,本文将从存储图的数据结构,最短路径的算法,以及最短路径算法和差分约束之间的相互转换关系来讨论。而基于最短路径的有一个著名的三角形不等式,即两边之和大于第三边或者两边只差小于第三边,a+b>c和a-b<c。

  1. 图的存储结构

    工欲善其事必先利其器,为了更好的理解最短路径,必须先了解存储图的数据结构。

    一般而言,图的存储方式,有按节点存储按边存储两种方式。
  • 传统来说,按节点存储的是临接矩阵存储方式,优点是实现简单,一个二维数组就能实现。但缺点也很明显,需要O(n^2)的存储空间。
/*
*a[i][j]代表的是以i为起点j为终点的边的权值。
*一般而言的初始化是先让要初始化的每个节点都为无穷大。然后再输入。
*/
int a[N][N];
  • 可是在大部分情况下,我们的边数远远没有打到O(n^2),这种情况下,我们可以选择按边存储。按边存储的主要存储方式是邻接表,前向星,以及链式前向星。
/*
*邻接表是为每个节点建立好边的关系,将与每一个定点连接的边连成一个链表。
*在C++中,有为我们封装好的list链表,可以直接使用。
*
*/
list<int> li[N];

/*
*前向星也是按边存储,通过构造结构体节点,存储每一条边的开始节点,终止节点,和边权值。
*再将所有节点数组按照开始节点的大小进行排序,就可以达到连续访问从一起点出发的边。
*但同时缺点也明显,需要进行一次排序,开销也比较大。
*/
struct edge{
    int u,v,w;
    edge(){}
    edge(int _u,int _v,int _w){
        u=_u;
        v=_v;
        w=_w;
    }
}
edge eg[N];
bool cmp(edge a,edge b){
    return a.u<b.u;
}
sort(eg,eg+N,cmp);

/*
*链式前向星按照我的理解,就是以数组的方式构造链表。
*每条边的next都是指向上一条以相同节点开始的边。
*head[u]指向的总是以u开头的最后一条加入的边的地址。
*/
struct edge1{
    int u,v,w,next;
    edge(){}
    edge(int _u,int _v,int _w,int _next){
        u=_u;
        v=_v;
        w=_w;
        next=_next;
    }
}
edge eg[N];
void addedge(int u,int v,int w){
    eg[count]=edge1(u,v,w,head[u]);
    head[u]=count++;
}

/*
*其实根本不用这么复杂的结构,c++提供给了我们vector容器。
*/
vector<edge> eg[N];
eg[u].push_back(edge(u,v,w));
  1. 最短路径算法

    聊完了基本的数据结构,既然本文是介绍最短路径之差分约束,接下来就讲介绍最短路径的算法。最短路径的算法一般而言,是分为两种,一种是正权边,一种是存在负权边。
  • 正权边,使用的是dijkstra算法,为了优化,一般加入优先队列进行使用。
/*
*节点的数据结构
*id代表节点的编号,value代表源点到这点的当前最短距离
*/
struct node{
    int id;
    int value;
    node(){}
    node(int _id,int _value){
        id=_id;
        value=_value;
    }
    bool operator < (const node &a)const{
        return value>a.value;
    }
}
struct edge{
    int u,v,w;
    edge(){}
    edge(int _u,int _v,int _w){
        u=_u;
        v=_v;
        w=_w;
    }
}
vector<edge>eg[N];//存储边,利用vector实现链式前向星。
bool vis[N];//该节点是否已经属于扩展过的,是就是true,否就是false。
int pre[N],dist[N];//pre[i]存储到i的上一个节点,dist[i]存储源点到i的当前最短距离。
void dijkstra(int s){
   priority_queue<node> que;
   que.push(node(s,0);
   while(!que.empty()){
       node temp=que.front();
       int u=temp.id;
       que.pop();
       vis[u]=true;
       for(int i=0;i<eg[u).size;i++){
           int v=eg[u][i].v;
           int w=eg[u][i].w;
           if(!vis[v]&&dist[v]>dist[u]+w){
               dist[v]=dist[u]+w;
               pre[v]=u;
               que.push(node(v,dist[v]);
           }
       }
   }
}
void init(){
    for(int i=0;i<n;i++){
        vis[i]=false;
        dist[i]=INF;//INF表示为不可达
        eg[i].clear();
    }
}
  1. 而当图中存在负权边时,就需要使用,bellman-ford算法或者spfa算法,下面我们将介绍spfa算法,可以将其视作是bellman-ford算法的优化版本。
/*
*
*/
struct node{
    int id;
    int value;
    node(){}
    node(int _id,int _value){
        id=_id;
        value=_value;
    }
    bool operator < (const node &a)const{
        return value>a.value;
    }
}
struct edge{
    int u,v,w;
    edge(){}
    edge(int _u,int _v,int _w){
        u=_u;
        v=_v;
        w=_w;
    }
}
bool inq[N];//标记定点是否在队列中,true表示在,flase表示不在
vector<edge> eg[N];//用vector来模拟链式前向星,或者说邻接表
int dist[N],visitcount[N];//dist[i]记录从源点到i的当前最短距离,visitcount[i]表示i节点被访问的次数;
void spfa(int s,int n){
    for(int i=0;i<=n;i++){
        inq[i]=0;
        visitcount[i]=0;
    }
    priority_queue<node> que;
    que.push(node(s,0));
    inq[s]=1;
    while(!que.empty()){
        node temp=que.front();
        int u=temp.id;
        que.pop();
        inq[u]++;
        if(visitcount[u]>n){
            cout<<"No answer!"<<endl;
        }
        for(int i=0;i<eg[u].size();i++){
            int v=eg[u][i].v;
            int w=eg[u][i].w;
            if(dist[v]>dist[u]+w){
                dist[v]=dist[u]+w;
                if(!inq[v]){
                    que.push(node(v,dist[v]));
                    inq[v]=true;
                }
            }
        }
    }
}

二、差分约束

1.差分约束的定义

如若一个系统由n个变量和m个不等式组成,并且这m个不等式对应的系数矩阵中每一行有且仅有一个1和-1,其它的都为0,这样的系统称为差分约束( difference constraints )系统。

即可以化为:

x[i]-x[j]<=ak

x[c]-x[d]>=ak1

...

x[n]-x[p]<=akn

也就是说,差分约束,就是一组不等式的集合。同时我们观察,我们用来求最短路径的方程,dist[u]> dist[v]+w,通过移项,可以看到,和差分约束的方程相同,实际上,我们可以把x[i]-x[j]<=ak看作是,从节点j指向节点i的一条边为ak的有向图。于是通过多个不等式的集合,我们可以相应的建出有向图。例如下图:

同时,我们可以从上面的介绍中看到x[i]-x[j]<=ak,x[i]-x[j]>=ak都是从i到j的一条边,边值是ak,但是有什么区别吗?

  • x[i]-x[j]<=ak,表示的是每一条边,都小于ak,所以我们可以看到,例如上图从0->3的路有三条,0->2->3 路径长度L1, 0->3路径长度L2,0->1->2->3路径长度L3三条路。
  • 所以实际上,不管我们怎么到达,都得满足全部约束,所以x[3]-x[0]<=min(L1,L2,L3)。也就是意味着,当我们在求从0到3的最短路径,就是在求满足约束情况下的最大值。
  • x[i]-x[j]>=ak,与上面相反,所得的实际结果应该是都大于每一条边,所求的x[3]-x[0]>=max(L1,L2,L3),所以求0到3的最长路径,就是求得在满足约束条件下的最小值。

原文地址:https://www.cnblogs.com/waaaafool/p/10558590.html

时间: 2024-08-24 13:27:55

最短路径之差分约束的相关文章

【转载】差分约束

一直不知道差分约束是什么类型题目,最近在写最短路问题就顺带看了下,原来就是给出一些形如x-y<=b不等式的约束,问你是否满足有解的问题 好神奇的是这类问题竟然可以转换成图论里的最短路径问题,下面开始详细介绍下 比如给出三个不等式,b-a<=k1,c-b<=k2,c-a<=k3,求出c-a的最大值,我们可以把a,b,c转换成三个点,k1,k2,k3是边上的权,如图 由题我们可以得知,这个有向图中,由题b-a<=k1,c-b<=k2,得出c-a<=k1+k2,因此比较

POJ 1201 Intervals(图论-差分约束)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20779   Accepted: 7863 Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a program that: reads the number of intervals, their end po

POJ1201 Intervals【SPFA】【差分约束】

Intervals Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 22307 Accepted: 8413 Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a program that: reads the number of intervals, their end points

zoj2770 差分约束问题

总的开说差分约束问题就是给出一系列不等式然后求问某一式子的最大值或者最小值. 差分约束问题详解: 比如有这样一组不等式: X1 - X2 <= 0 X1 - X5 <= -1 X2 - X5 <= 1 X3 - X1 <= 5                   不等式组(1) X4 - X1 <= 4 X4 - X3 <= -1 X5 - X3 <= -3 X5 - X4 <= -3 全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就

【转载】夜深人静写算法(四)——差分约束

[转载]夜深人静写算法(四) - 差分约束  目录     一.引例       1.一类不等式组的解   二.最短路       1.Dijkstra       2.图的存储       3.链式前向星       4.Dijkstra + 优先队列       5.Bellman-Ford       6.SPFA       7.Floyd-Warshall   三.差分约束        1.数形结合        2.三角不等式        3.解的存在性        4.最大值

Candies---hdu3159(spfa+差分约束)

题目链接:http://poj.org/problem?id=3159 题意:有n个小孩,m个关系格式是A B C 表示小孩 B 的糖果数最多比小孩A多C个,相当于B-A<=C; 有m个这样的关系最后求小孩n比小孩1最多多几个糖果: 差分约束: 比如给出三个不等式,b-a<=k1,c-b<=k2,c-a<=k3,求出c-a的最大值, 我们可以把a,b,c转换成三个点,k1,k2,k3是边上的权,如图   由题我们可以得知,这个有向图中,由题b-a<=k1,c-b<=k2

差分约束小结

ZOJ 2770 Burn the Linked Camp /* ZOJ 2770 Burn the Linked Camp 差分约束 */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int MAXN = 1009; struct Edge { int v, ne, c; } G[MAXN*MAXN]

shortpath3159差分约束

题目意思: flymouse是幼稚园班上的班长,一天老师给小朋友们买了一堆的糖果,由flymouse来分发,在班上,flymouse和snoopy是死对头,两人势如水火,不能相容,因此fly希望自己分得的糖果数尽量多于snoopy,而对于其他小朋友而言,则只希望自己得到的糖果不少于班上某某其他人就行了. 比如A小朋友强烈希望自己的糖果数不能少于B小朋友m个,即B- A<=m,A,B分别为 A.B小朋友的分得的糖果数.因此根据题意,可以列出如下的不等式:         Sbi-Sai<=ci(

K - Candies(最短路+差分约束)

题目大意:给N个小屁孩分糖果,每个小屁孩都有一个期望,比如A最多比B多C个,再多了就不行了,会打架的,求N最多比1多几块糖 分析:就是求一个极小极大值...试试看 这里需要用到一个查分约束的东西 下面是查分约束详解: 一直不知道差分约束是什么类型题目,最近在写最短路问题就顺带看了下,原来就是给出一些形如x-y<=b不等式的约束,问你是否满足有解的问题 好神奇的是这类问题竟然可以转换成图论里的最短路径问题,下面开始详细介绍下 比如给出三个不等式,b-a<=k1,c-b<=k2,c-a<