差分约束系统

30 篇文章 0 订阅
14 篇文章 1 订阅

差分约束系统,就是对于一段序列{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 ;
}

最后,感谢光叭叭叭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值