差分约束系统,就是对于一段序列{x[i]},存在一些条件,例如xi−xj≥bk,求是否存在符合条件的区间。
其实这和图论有着很大的关系
考虑最短路中的松弛:
if ( d[u] > d[x] + w[i] )
d[u] = d[x] + w[i] ;
很巧的是,我们的约束不正好可以变成a>b+c的形式吗?
于是,对于约束条件xi−xj≥b,正好可以看做从点j往点i添加了一条权值为b的边。
那么现在问题就迎刃而解了!
注意,对于不同的不等号,可能要添加负边,具体请依照实际情况。
给几个例题
洛谷1993 小K的农场
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
#include <cmath>
#include <algorithm>
#include <ctime>
using namespace std ;
const int maxn = 100010, zhf = 1<<29 ;
inline void Read ( int &x ) {
char c = getchar() ; bool f = 0 ; x = 0 ;
while ( !isdigit(c) ) {
if ( c == '-' ) f = 1 ;
c = getchar() ;
}
while ( isdigit(c) ) {
x = 10 * x + c - '0' ;
c = getchar() ;
} if (f) x = -x ;
}
int n, m, d[maxn], e, to[maxn<<1], nxt[maxn<<1], be[maxn], w[maxn<<1] ;
void init() {
for ( int i = 0 ; i < maxn ; i ++ )
d[i] = zhf ;
}
void add ( int x, int y, int z ) {
to[++e] = y ;
nxt[e] = be[x] ;
be[x] = e ;
w[e] = z ;
}
bool inq[maxn] ;
bool spfa ( int x ) {
inq[x] = 1 ;
int i, u ;
for ( i = be[x] ; i ; i = nxt[i] ) {
u = to[i] ;
if ( d[u] > d[x] + w[i] ) {
d[u] = d[x] + w[i] ;
if ( inq[u] ) return false ;
if ( !spfa(u) ) return false ;
}
}
inq[x] = 0 ;
return true ;
}
int main() {
int i, j, k, u, v, a, b, cmd, c ;
Read(n) ; Read(m) ;
init() ;
while (m--) {
Read(cmd) ;
if ( cmd == 1 ) {
Read(a) ; Read(b) ; Read(c) ;
add ( a, b, -c ) ;
} else if ( cmd == 2 ) {
Read(a) ; Read(b) ; Read(c) ;
add ( b, a, c ) ;
} else {
Read(a) ; Read(b) ;
add ( a, b, 0 ) ;
add ( b, a, 0 ) ;
}
}
for ( i = 1 ; i <= n ; i ++ ) add ( 0, i, 0 ) ;
d[0] = 0 ;
memset ( inq, 0, sizeof(inq) ) ;
if ( spfa(0) ) puts("Yes") ;
else puts("No") ;
return 0 ;
}
洛谷1250 种树
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
#include <cmath>
#include <algorithm>
#include <ctime>
using namespace std ;
const int maxn = 50010, maxm = maxn<<4, zhf = 1<<29 ;
int q[maxn<<1] ;
inline void Read ( int &x ) {
char c = getchar() ; bool f = 0 ; x = 0 ;
while ( !isdigit(c) ) {
if ( c == '-' ) f = 1 ;
c = getchar() ;
}
while ( isdigit(c) ) {
x = 10 * x + c - '0' ;
c = getchar() ;
} if (f) x = -x ;
}
int n, m, be[maxn], nxt[maxm], to[maxm], w[maxm], d[maxn], e ;
bool inq[maxn] ;
void add ( int x, int y, int z ) {
to[++e] =y ;
nxt[e] = be[x] ;
be[x] = e ;
w[e] = z ;
}
void spfa ( int S ) {
int i, u, x, head=0, tail=1 ;
d[S] = 0 ;
inq[S] = 1 ;
q[1] = S ;
while ( head!=tail ) {
x = q[head = (head+1) % maxn];
//printf ( "d[%d] = %d\n", x, d[x] ) ;
//system("pause") ;
for ( i = be[x] ; i ; i = nxt[i] ) {
u = to[i] ;
if ( d[u] > d[x] + w[i] ) {
d[u] = d[x] + w[i] ;
if ( !inq[u] ) {
inq[u] = 1 ;
q[ tail=(tail+1)%maxn ] = u ;
}
}
}
inq[x] = false ;
}
}
int main() {
int i, j, k, x, y, z ;
Read(n) ; Read(m) ;
while (m--) {
Read(x) ; Read(y) ; Read(z) ;
add ( y, x-1, -z ) ;
}
for ( i = 0 ; i < maxn ; i ++ ) d[i] = zhf ;
for ( i = 1 ; i <= n ; i ++ ) {
add ( i, i-1, 0 ) ;
add ( i-1, i, 1 ) ;
}
for ( i = 0 ; i <= n ; i ++ )
add ( n+1, i, 0 ) ;
memset ( inq, 0, sizeof(inq) ) ;
spfa(n+1) ;
int md = zhf ;
for ( i = 0 ; i <= n ; i ++ )
md = min ( md, d[i] ) ;
printf ( "%d\n", d[n]-md ) ;
return 0 ;
}
SCOI2011 洛谷3275 糖果
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
#include <cmath>
#include <algorithm>
#include <ctime>
#define ll long long
using namespace std ;
const ll zhf = 1<<30 ;
const ll maxn = 100010, maxm = 500010 ;
bool Read ( ll &x ) {
bool f = 0 ; x = 0 ; char c = getchar() ;
while ( !isdigit(c) ) {
if ( c == '-' ) f = 1 ;
if ( c == EOF ) return false ;
c = getchar() ;
}
while ( isdigit(c) ) {
x = 10 * x + c - '0' ;
c = getchar() ;
}
if ( f ) x = -x ;
return true ;
}
ll n, m, d[maxn], cnt[maxn] ;
ll e, be[maxn], to[maxm], nxt[maxm], w[maxm] ;
bool inq[maxn] ;
queue <ll> q ;
void add ( ll x, ll y, ll z ) {
to[++e] = y ;
nxt[e] = be[x] ;
w[be[x] = e] = z ;
}
ll spfa ( ll st ) {
while ( !q.empty() ) q.pop() ;
ll i, u, x, v ;
for ( i = 0 ; i < maxn ; ++ i )
d[i] = -zhf, inq[i] = false;
q.push(st) ;
inq[st] = true ;
d[st] = 0 ;
while ( !q.empty() ) {
x = q.front() ;
q.pop() ;
inq[x] = false ;
for ( i = be[x] ; i ; i = nxt[i] ) {
u = to[i] ;
if ( d[u] < d[x] + w[i] ) {
d[u] = d[x]+w[i] ;
if ( !inq[u] ) {
inq[u] = true ;
q.push(u) ;
if ( ++cnt[u] >= n ) return -1 ;
}
}
}
}
return d[n] ;
}
int main() {
ll i, j, k, A, B, cmd ;
bool end = false ;
Read(n) ; Read(m) ;
while (m--) {
Read(cmd) ; Read(A) ; Read(B) ;
if ( end ) continue ;
if ( cmd == 1 ) {
add ( A, B, 0 ) ;
add ( B, A, 0 ) ;
} else if ( cmd == 2 ) {
if ( A == B ) end = 1 ;
else add ( A, B, 1 ) ;
}
else if ( cmd == 3 ) add ( B, A, 0 ) ;
else if ( cmd == 4 ) {
if ( A == B ) end = 1 ;
else add ( B, A, 1 ) ;
}
else add ( A, B, 0 ) ;
}
if ( end ) { puts("-1") ; return 0 ; }
for ( i = n ; i ; -- i )
add ( 0, i, 1 ) ;
ll ans = spfa(0), sum = 0 ;
if ( ans == -1 ) {
puts("-1") ;
return 0 ;
}
for ( i = n ; i ; -- i )
sum += d[i] ;
printf ( "%lld\n", sum ) ;
return 0 ;
}
最后,感谢光叭叭叭。