知识点 - 差分约束系统

知识点 - 差分约束系统

解决问题类型:

背景是给你若干个不等式,形如 x i − x j ≤ b xi−xj≤b xixjb,需要你判断x的解的存在性或是最优解

而差分约束系统即为这个问题转化为一个图论问题,进而跑最短路来判环或求最值距离(最优解)。
这里转化的原理是三角不等式,即 d ( v ) − d ( u ) ≤ c o s t ( u , v ) d(v)−d(u)≤cost(u,v) d(v)d(u)cost(u,v),可以建为一条花费为 c o s t ( u , v ) cost(u,v) cost(u,v)的边 ( u , v ) (u,v) (u,v)

复杂度:

O ( n 2 ) O(n^2) O(n2)

实现

  1. 与最短路之间的联系

    先给出结论:求解差分约束系统,都可以转化成图论的单源最短路径(或最长路径)问题。

    我们观察上面例子中的不等式,都是 x [ i ] − x [ j ] &lt; = a [ k ] x[i] - x[j] &lt;= a[k] x[i]x[j]<=a[k],可以进行移项,成为 x [ i ] &lt; = x [ j ] + a [ k ] x[i] &lt;= x[j] + a[k] x[i]<=x[j]+a[k],我们令 a [ k ] = w ( j , i ) a[k] = w(j, i) a[k]=w(j,i) d i s [ i ] = x [ i ] dis[i]=x[i] dis[i]=x[i],并使 i = v , j = u i=v,j=u i=v,j=u,那么原始就变为: d i s [ u ] + w ( u , v ) &gt; = d i s [ v ] dis[u]+w(u,v)&gt;=dis[v] dis[u]+w(u,v)>=dis[v],于是可以联想到最短路模型中的一部分代码

    if(dis[u]+w(u,v)<=dis[v]){
        dis[v]=dis[u]+w(u,v);
    }
    

    这不正与松弛操作相似吗?

    但是好像不等号方向刚好相反,但其实这并不矛盾

    上面的代码要实现的是使 d i s [ u ] + w ( u , v ) &gt; d i s [ v ] dis[u]+w(u,v)&gt;dis[v] dis[u]+w(u,v)>dis[v],而对于不等式,我们进行建边的操作:对于每个不等式 x [ i ] − x [ j ] &lt; = a [ k ] x[i] - x[j] &lt;= a[k] x[i]x[j]<=a[k],对结点 j j j i i i 建立一条 j − &gt; i j -&gt; i j>i的有向边,边权为 a [ k ] a[k] a[k],求 x [ n − 1 ] − x [ 0 ] x[n-1] - x[0] x[n1]x[0] 的最大值就是求 0 到n-1的最短路,两者刚好吻合。所以求解差分约束问题就转化为了最短路问题。

  2. 问题解的存在性

    由于在求解最短路时会出现存在负环或者终点根本不可达的情况,在求解差分约束问题时同样存在

    (1)、存在负环

    如果路径中出现负环,就表示最短路可以无限小,即不存在最短路,那么在不等式上的表现即 X [ n − 1 ] − X [ 0 ] &lt; = T X[n-1] - X[0] &lt;= T X[n1]X[0]<=T中的T无限小,得出的结论就是 X [ n − 1 ] − X [ 0 ] X[n-1] - X[0] X[n1]X[0]的最大值不存在。在SPFA实现过程中体现为某一点的入队次数大于节点数。(貌似可以用 ( n u m n o d e ) \sqrt{(num_{node})} (numnode) 来代替减少运行时间)

    (2)、终点不可达

    这种情况表明 X [ n − 1 ] X[n-1] X[n1] X [ 0 ] X[0] X[0]之间没有约束关系, X [ n − 1 ] − X [ 0 ] X[n-1] - X[0] X[n1]X[0]的最大值无限大,即 X [ n − 1 ] X[n-1] X[n1] X [ 0 ] X[0] X[0]的取值有无限多种。在代码实现过程中体现为 d i s [ n − 1 ] = I N F dis[n-1]=INF dis[n1]=INF

  3. 不等式转换

    做题时可能会遇到不等式中的符号不相同的情况,但我们可以对它们进行适当的转化

    (1)方程给出: X [ n − 1 ] − X [ 0 ] &gt; = T X[n-1]-X[0]&gt;=T X[n1]X[0]>=T ,可以进行移项转化为: X [ 0 ] − X [ n − 1 ] &lt; = − T X[0]-X[n-1]&lt;=-T X[0]X[n1]<=T

    (2)方程给出: X [ n − 1 ] − X [ 0 ] &lt; T X[n-1]-X[0]&lt;T X[n1]X[0]<T, 可以转化为 X [ n − 1 ] − X [ 0 ] &lt; = T − 1 X[n-1]-X[0]&lt;=T-1 X[n1]X[0]<=T1

    (3)方程给出: X [ n − 1 ] − X [ 0 ] = T X[n-1]-X[0]=T X[n1]X[0]=T,可以转化为 X [ n − 1 ] − X [ 0 ] &lt; = T &amp; &amp; X [ n − 1 ] − X [ 0 ] &gt; = T X[n-1]-X[0]&lt;=T\&amp;\&amp;X[n-1]-X[0]&gt;=T X[n1]X[0]<=T&&X[n1]X[0]>=T,再利用(1)进行转化即可

  4. 应用

    对于不同的题目,给出的条件都不一样,我们首先需要关注问题是什么,如果需要求的是两个变量差的最大值,那么需要将所有不等式转变成"<=“的形式,建图后求最短路;相反,如果需要求的是两个变量差的最小值,那么需要将所有不等式转化成”>=",建图后求最长路。

例题

POJ 1716 Integer Intervals

HDOJ 3666 THE MATRIX PROBLEM

代码

SPFA求最短路

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1010;
const int inf=1e9;
struct edge{
    int v,cost;
    edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}
};
vector<edge>E[maxn];
bool vis[maxn];
int cnt[maxn],dist[maxn],s,n;

void addedge(int u,int v,int w)
{
    E[u].push_back(edge(v,w));
}

bool SPFA()
{
    memset(vis,false,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for ( int i=1;i<=n;i++ ) dist[i]=inf;
    vis[s]=true;
    dist[s]=0;
    queue<int>que;
    que.push(s);
    cnt[s]=1;
    while ( !que.empty() ) {
        int u=que.front();
        que.pop();
        vis[u]=false;
        for ( int i=0;i<E[u].size();i++ ) {
            int v=E[u][i].v;
            int cost=E[u][i].cost;
            if ( dist[v]>dist[u]+cost ) {
                dist[v]=dist[u]+cost;
                if ( !vis[v] ) {
                    vis[v]=true;
                    que.push(v);
                    if ( ++cnt[v]>n ) return false;
                }
            }
        }
    }
    return true;
}

最长路模板:即将边权取负,最后的结果取负即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值