加载中...

差分约束

差分约束系统用于求解一组特殊的 N 元一次不等式组. 它包含了 N 个变量 x1 ~ xnM 个约束条件, 其中每个约束条件形如: \(x_i \leqslant x_j + c_k\) (最短路) , \(x_i \geqslant x_j +c_k\) (最长路)

约束条件 \(x_i \leqslant x_j +c_k\) , 可转化为一条有向边 \(j \stackrel{c_k}{\rightarrow} i\) , 最短路中有 dist[i] <= dist[j] + ck


差分约束

(1) 求不等式组的可行解

\(\quad\) 源点需要满足的条件: 从源点出发, 一定可以走到所有的边

\(\quad\) 步骤:

\(\quad\) [1] 先找到每个不等式 \(x_i \leqslant x_j + c_k\) 转化成一条从 j 走到 i , 长度为 ck 的边

\(\quad\) [2] 找到一个源点, 使得该源点一定可以遍历到所有边

\(\quad\) [3] 从源点求一遍单源最短路

\(\quad\) \(\quad\) 结果1: 如果存在负环, 则原不等式组一定无解

\(\quad\) \(\quad\) 结果2: 如果没有负环, 则 dist[i] 就是原不等式组的一个可行解

(2) 如果求最大值或者最小值, 这里的最值指的是每个变量的最值

\(\quad\) 结论: 如果求的是最小值, 则应该求最长路; 如果求的是最大值, 则应该求最短路

\(\quad\) 问题: 如何转化 \(x_i \leqslant c\) , 其中 c 是一个常数, 这类的不等式

\(\quad\) 方法: 建立一个超级源点, 0 , 建立 \(0 \stackrel{c}{\rightarrow} i\) 的边

\(\quad\)xi 的最大值, 即求对 xi 的所有约束条件中的最小值/ 最小上界 (最短路)

最小值 : 最长路 \(\Longrightarrow\) 大于号 \(\Longrightarrow\) \(x_i \geqslant x_j + c_k\)

最大值 : 最短路 \(\Longrightarrow\) 小于号 \(\Longrightarrow\) \(x_i \leqslant x_j + c_k\)


当存在负环/ 正环时, spfa 用栈处理比用堆处理更快

//spfa判断是否有正环(栈实现)
//单源最长路,求最小值

bool spfa ()
{
    int hh=0,tt=1;
    memset(dist,-0x3f,sizeof dist);
    dist[0]=0;
    q[0]=0;
    st[0]=true;
    
    while(hh!=tt)
    {
        int t=q[--tt];
        st[t]=false;
        
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]<dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n+1)return true;	//包含源点0
                if(!st[j])
                {
                    q[tt++]=j;
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
//spfa判断是否有负环(堆实现)
//单源最短路,求最大值

bool spfa ()
{
    int hh=0,tt=1;
    memset(dist,0x3f,sizeof dist);
    dist[0]=0;
    q[0]=0;
    st[0]=true;
    
    while(hh!=tt)
    {
        int t=q[hh++];
        if(hh==N)hh=0;
        st[t]=true;
        
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n+1)return true;	//包含源点0
                if(!st[j])
                {
                    q[tt++]=j;
                    if(tt==N)tt=0;
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
posted @ 2023-04-30 15:35  邪童  阅读(36)  评论(0编辑  收藏  举报