差分约束系统
Posted TURNINING
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了差分约束系统相关的知识,希望对你有一定的参考价值。
差分约束系统是指由一系列约束条件成的不等式组, 形如:
即全部是关于两未知数差的不等式
一般关于差分约束的题目有两种问法
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)就是最小解。
关于建图,一般题目不会给那么直接的图给你建得自己转换
- x1 - x2 = y -> x1 - x2 <= y 且 x1 - x2 >= y
- x1 - x2 < y -> x1 - x2 <= y - 1
- x1 - x2 > y -> x1 - x2 >= y - 1
- x1/x2 >= a -> log(x1) - log(x2) >= log(a) -> x1 - x2 >= log(a)
- 区间问题的相邻两项 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()差分约束系统