差分约束
差分约束
建图套路:
\(B-A\le c\ \rightarrow dis[B]\le dis[A]+c\) 那么可以类比 \(spfa\) 的更新方式 从 \(A\) 向 \(B\) 连一条边权为 \(c\) 的边即可
对于 \(B=A\) 的条件 可以类比为 \(B-A\le0\) 且 \(A-B\le0\) 那么从 \(A\) 向 \(B\) 连 \(0\) 边 同时反向连 \(0\) 边即可
最后看有没有负环 负环就是无解情况
P1993 小 K 的农场
判断负环还是需要用判断最短路条数的写法...否则就寄了
注意我们建立了一个超级源点来保证图连通 那么我们判断负环的时候需要判断 \(cnt[v]=n+1\) 而不是 \(n\)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
const int N = 5e3 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , cnt[N] , in[N] , dis[N] , s;
int q[10000000] , head = 1 , tail;
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
int spfa()
{
memset ( dis , inf , sizeof dis );
dis[s] = 0 , in[s] = 1 , q[++tail] = s;
while ( head <= tail )
{
int u = q[head++]; in[u] = 0;
for ( auto [v,w] : e[u] )
if ( dis[v] > dis[u] + w )
{
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if ( cnt[v] >= n + 1 ) return 0;
if ( !in[v] ) q[++tail] = v , in[v] = 1;
}
}
return 1;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) add ( s , i , 0 );
for ( int i = 1 ; i <= m ; i ++ )
{
int op = read() , u = read() , v = read() , w;
if ( op == 1 ) w = read() , add ( u , v , -w );
if ( op == 2 ) w = read() , add ( v , u , w );
if ( op == 3 ) add ( u , v , 0 ) , add ( v , u , 0 );
}
cout << ( spfa() == 0 ? "No" : "Yes" ) << endl;
return 0;
}
P5960 【模板】差分约束
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
#define int long long
const int N = 5e3 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , dis[N] , in[N] , cnt[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
queue<int> q;
int spfa ( int s )
{
memset ( dis , inf , sizeof dis );
q.push(s) , in[s] = 1 , dis[s] = 0;
while ( !q.empty() )
{
int u = q.front(); q.pop(); in[u] = 0;
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( dis[v] > dis[u] + w )
{
dis[v] = dis[u] + w , cnt[v] = cnt[u] + 1;
if ( cnt[v] >= n + 1 ) return 0;
if ( !in[v] ) q.push(v) , in[v] = 1;
}
}
}
return 1;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) add ( 0 , i , 0 );
for ( int i = 1 , u , v , w ; i <= m ; i ++ ) u = read() , v = read() , w = read() , add ( v , u , w );
if ( !spfa(0) ) return cout << "NO" << endl , 0;
for ( int i = 1 ; i <= n ; i ++ ) cout << dis[i] << ' ';
return 0;
}