差分约束系统

Posted TURNINING

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了差分约束系统相关的知识,希望对你有一定的参考价值。

差分约束系统是指由一系列约束条件成的不等式组, 形如:
x都是未知量
即全部是关于两未知数差的不等式

一般关于差分约束的题目有两种问法

1、是否有解?
2、最大解或者最小解

解决方法
1:设一个超级源点,与每个节点连一条权值为0的边(防止图不连通),然后建图跑最短路,若存在负环即代表最短路不存在,无解。若存在最短路则有解。

2:稍微麻烦一点。
当问最大解时,我们可以把不等式化为 d(v) >= d(u) + w(u, v) 的形式,与最短路的三角不等式类似,建一条从u到v的边即可,然后跑最短路,最短路d(v)就是最大解。

当问最小解时,把不等式化为d(v) <= d(u) + w(u, v)的形式,建一条从u到v的边,跑最长路,最长路d(v)就是最小解。

关于证明可以看一下这两篇文章传送门1 传送门2

关于建图,一般题目不会给那么直接的图给你建得自己转换

  1. x1 - x2 = y -> x1 - x2 <= y 且 x1 - x2 >= y
  2. x1 - x2 < y -> x1 - x2 <= y - 1
  3. x1 - x2 > y -> x1 - x2 >= y - 1
  4. x1/x2 >= a -> log(x1) - log(x2) >= log(a) -> x1 - x2 >= log(a)
  5. 区间问题的相邻两项 i - (i-1) >= 0 且 i - (i-1) <= 1,排队问题 i - (i-1) >= 0

一些题目
POJ1201
注意题目的一些隐含条件,设xi为前i项选的个数,那么有xi - xi-1 >= 0, xi - xi-1 <= 1, 跑最长路

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

typedef pair<int, int> PI;
typedef pair<double, double> PD;
 
const int MAXN = 5e4 + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;

struct edge { int to, cost; };

vector<edge> g[MAXN];
int vis[MAXN], cnt[MAXN], dis[MAXN];

int n, t;

bool spfa() {
    fill(dis, dis+1+t, -INF);
    fill(vis, vis+1+t, 0);
    queue<int> que; 
    que.push(0);
    cnt[0] = vis[0] = 1;
    dis[0] = 0;

    while(!que.empty()) {
        int v = que.front(); que.pop();
        vis[v] = 0;
        for(int i = 0; i < g[v].size(); i++) {
            edge &e = g[v][i];
            if(dis[e.to] < dis[v] + e.cost) {
                dis[e.to] = dis[v] + e.cost;
                if(!vis[e.to]) {
                    vis[e.to]++;
                    cnt[e.to]++;
                    if(cnt[e.to] > n) return true;
                    que.push(e.to);
                } 
            }
        }
    }
    return false;
}


void solve() {  
    t = 0;
    scanf("%d", &n);
    int v, u, w;
    for(int i = 0;  i <= 50001; i++) g[i].clear();
    for(int i = 1; i <= n; i++) {
        scanf("%d %d %d", &v, &u, &w);
        v++; u++;
        t = max(max(v, u), t);
        g[v-1].push_back(edge{u, w});
    }
    for(int i = 1; i <= t; i++) {
        g[i-1].push_back(edge{i, 0});
        g[i].push_back(edge{i-1, -1});
    }
    spfa();
    printf("%d\\n", dis[t]);
}

int main() {
    //ios::sync_with_stdio(false);
    int t = 1; //scanf("%d", &t);
    while(t--) {
        solve();
    }
    return 0;
}

POJ3169
老经典的题了,建图跑最短路,注意牛是按编号顺序排的

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

typedef pair<int, int> PI;
typedef pair<double, double> PD;
 
const int MAXN = 1e3 + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;

struct edge { int to, cost; };

vector<edge> g[MAXN];
int vis[MAXN], cnt[MAXN], dis[MAXN];

int n, ML, MD;

bool spfa() {
    fill(dis+1, dis+1+n, INF);
    queue<int> que; que.push(1);
    cnt[1] = vis[1] = 1;
    dis[1] = 0;

    while(!que.empty()) {
        int v = que.front(); que.pop();
        vis[v] = 0;
        for(int i = 0; i < g[v].size(); i++) {
            edge &e = g[v][i];
            if(dis[e.to] > dis[v] + e.cost) {
                dis[e.to] = dis[v] + e.cost;
                if(!vis[e.to]) {
                    vis[e.to]++;
                    cnt[e.to]++;
                    if(cnt[e.to] > n) return true;
                    que.push(e.to);
                } 
            }
        }
    }
    return false;
}


void solve() {  
    scanf("%d %d %d", &n, &ML, &MD);
    int v, u, w;
    for(int i = 1; i <= ML; i++) {
        scanf("%d %d %d", &v, &u, &w);
        g[v].push_back(edge{u, w});
    }
    for(int i = 1; i <= MD; i++) {
        scanf("%d %d %d", &v, &u, &w);
        g[u].push_back(edge{v, -w});
    }
    for(int i = 2; i <= n; i++) {
        g[i].push_back(edge{i-1, 0});
    }

    if(spfa()) puts("-1");
    else if(dis[n] == INF) puts("-2");
    else printf("%d\\n", dis[n]);
}

int main() {
    //ios::sync_with_stdio(false);
    int t = 1; //scanf("%d", &t);
    while(t--) {
        solve();
    }
    return 0;
}

P1993 小 K 的农场
要稍微转换一下不等式

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

typedef pair<int, int> PI;
typedef pair<double, double> PD;
 
const int MAXN = 5e3 + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;

struct edge { int to, cost; };

vector<edge> g[MAXN];
int vis[MAXN], cnt[MAXN], dis[MAXN];

int n, m;

bool spfa() {
    fill(dis+1, dis+1+n, INF);
    queue<int> que; que.emplace(0);
    cnt[0] = vis[0] = 1;
    while(!que.empty()) {
        int v = que.front(); que.pop();
        vis[v] = 0;
        for(int i = 0; i < g[v].size(); i++) {
            edge &e = g[v][i];
            if(dis[e.to] > dis[v] + e.cost) {
                dis[e.to] = dis[v] + e.cost;
                if(!vis[e.to]) {
                    vis[e.to]++;
                    cnt[e.to]++;
                    if(cnt[e.to] > n + 1) return true;
                    que.emplace(e.to);
                } 
            }
        }
    }
    return false;
}


void solve() {  
    scanf("%d %d", &n, &m);
    int op, a, b, c;
    for(int i = 1; i <= m; i++) {
        scanf("%d", &op);
        if(op == 1) {
            scanf("%d %d %d", &a, &b, &c);
            g[a].emplace_back(edge{b, -c});
        }
        else if(op == 2) {
            scanf("%d %d %d", &a, &b, &c);
            g[b].emplace_back(edge{a, c});
        }
        else {
            scanf("%d %d", &a, &b);
            g[a].emplace_back(edge{b, 0});
            g[b].emplace_back(edge{a, 0});
        }
    }
    for(int i = 1; i <= n; i++) g[0].emplace_back(edge{i, 0});
    if(spfa()) puts("No");
    else puts("Yes");
}

int main() {
    //ios::sync_with_stdio(false);
    int t = 1; //scanf("%d", &t);
    while(t--) {
        solve();
    }
    return 0;
}

POJ3666
不等式两边同时取对数,这个建图属实是惊艳到我了…

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

typedef pair<int, int> PI;
typedef pair<double, double> PD;
 
const int MAXN = 1000 + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;

\\
struct edge { int to; double cost; };

int n, m, L, R;
int vis[MAXN], cnt[MAXN];
double d[MAXN];
vector<edge> g[MAXN];

bool spfa(int t) {
    fill(cnt, cnt+n+m+1, 0);
    fill(vis, vis+n+m+1, 0);
    fill(d, d+n+m+1, INF);
    d[0] = 0;
    cnt[0] = vis[0] = 1;
    queue<int> que; que.emplace(0);
    while(!que.empty()差分约束系统

差分约束系统

差分约束系统

差分约束系统

差分约束系统总结(转)

初涉差分约束系统