前置知识
例题
给定一组不等式
观察这些式子,好像方法不是很明确。
然后前人经过研究,发现这个问题的解法和最短路有关。
在讲各种最短路方法时,有一点是共同的,那就是
if(d[v]>d[u]+w[e])
d[v]=d[u]+w[e];
这个在最短路算法中叫做松弛操作,其中 为有向边 的终点。
显然,当最短路求出后,所有的 都会小于等于 (大于的都会被松弛掉)
显然由 可推出
对于不等式
,我们从
到
连权值为
的有向边,那么我们有
将所有的不等式执行该操作后,
即为该不等式的一组解
对于不等式无解的情况,就是该图无最短路的情况,只有负环的出现会造成这种局面
而我们的 可以轻松胜任找负环的工作。
注意
上文给出的是基于最短路的差分约束系统,用最长路可以通过 来实现差分约束系统,方法同上。
Code(bfs+最长路)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int first[1000005],nxt[1000005],to[1000005],w[1000005],tot=0;
int inq[100005],dis[100005],cnt[100005];
void Add(int x,int y,int z){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
w[tot]=z;
}
inline int Read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
inline void Write(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9){
Write(x/10);
}
putchar(x%10+'0');
}
bool spfa(int n){
queue<int> q;
q.push(0);
inq[0]=1;
while(!q.empty()){
int u=q.front();
q.pop();
if(cnt[u]==n-1) return false;
cnt[u]++;
inq[u]=0;
for(int e=first[u];e;e=nxt[e]){
int v=to[e];
if(dis[v]<dis[u]+w[e]){
dis[v]=dis[u]+w[e];
if(!inq[v]){
inq[v]=1;
q.push(v);
}
}
}
}
return true;
}
signed main(){
int n=Read(),m=Read();
for(int i=1;i<=m;i++){
int x=Read(),a=Read(),b=Read();
if(x==1){
Add(a,b,0);
Add(b,a,0);
}
if(x==2){
if(a==b){
cout<<"-1\n";
return 0;
}
Add(a,b,1);
}
if(x==3) Add(b,a,0);
if(x==4){
if(a==b){
cout<<"-1\n";
return 0;
}
Add(b,a,1);
}
if(x==5) Add(a,b,0);
}
for(int i=n;i>=1;i--){ //加边顺序优化
Add(0,i,1);
}
if(!spfa(n)){
cout<<"-1\n";
return 0;
}
int ans=0;
for(int i=1;i<=n;i++){
ans+=dis[i];
}
cout<<ans<<endl;
}
UPD:2019.10.13
对于找负环来说,实测
版spfa比
快100倍左右。
例题:小k的农场
Code(dfs+最短路)
#include<bits/stdc++.h>
#define inf 2147483647
using namespace std;
inline int Read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
inline void Write(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9){
Write(x/10);
}
putchar(x%10+'0');
}
int first[200005],nxt[200005],to[200005],w[200005],tot=0;
void Add(int x,int y,int z){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
w[tot]=z;
}
int n,m,d[200005],inq[200005],cnt[200005];
bool spfa(int u){
inq[u]=1;
for(int e=first[u];e;e=nxt[e]){
int v=to[e];
if(d[v]>d[u]+w[e]){
d[v]=d[u]+w[e];
if(inq[v]) return false;
if(!spfa(v)) return false;
}
}
inq[u]=0;
return true;
}
signed main(){
n=Read(),m=Read();
int opt,a,b,c;
for(int i=1;i<=n;i++){
Add(0,i,1);
}
for(int i=1;i<=m;i++){
opt=Read();
if(opt==3){
a=Read(),b=Read();
Add(a,b,0);
Add(b,a,0);
}
if(opt==2){
a=Read(),b=Read(),c=Read();
Add(b,a,c);
}
if(opt==1){
a=Read(),b=Read(),c=Read();
Add(a,b,-c);
}
}
memset(d,10,sizeof(d));
d[0]=0;
if(spfa(0)) cout<<"Yes\n";
else cout<<"No\n";
}