差分约束系统
- 对于多组形如(B-A geq C) 的不等式组求出一组解,其中,(A) 、(B) 为变量,(C) 为常数
转化为$$A+Cleq B$$,注意到该形式形似于SPFA松弛过程中的三角形不等式 $$dis[u]+w(u,v)leq dis[v]$$
于是,连一条(A)到(B)的长度为(C)的有向边。因为建出的图可能不连通,最后规定一个源点s(通常为0号点或n+1号点)对每个点连一条长度为k的边,进行SPFA,存在正环则无解,否则dis数组的值对应每个变量取值,满足所有变量取值都大于等于最初从源点连的边权k。
- 本题的五种情况(所有变量取值均为正整数):
- (A=B) 转化为 (A+0leq B) 和 (B+0leq A)
- (A<B) 转化为(A+1leq B)
- (A>B) 转化为 (B+1leq A)
- (Aleq B) 转化为 (A+0 leq B)
- (Ageq B) 转化为 (B+0leq A)
- 需要 SPFA dfs版 以及 反向连边 否则会TLE (
面向数据编程)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100005,maxm=100005,inf=0x3f3f3f3f;
int n,m,tot,dis[maxn],cnt[maxn];
long long ans;
bool v[maxn];
struct edge{
#define New(p) p=&e[++tot]
int to,dis;edge *Nex;
}e[maxm*3],*head[maxn];
inline void add(int x,int y,int z){
edge *p;New(p);p->dis=z;p->to=y;p->Nex=head[x];head[x]=p;
}
bool SPFA(int u=0){
v[u]=true;
for(edge *i=head[u];i!=NULL;i=i->Nex){
if(dis[u]+i->dis>dis[i->to]){
dis[i->to]=dis[u]+i->dis;
if(v[i->to]) return false;
if(!SPFA(i->to)) return false;
}
}
v[u]=false;
return true;
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1,flag,x,y;i<=m;++i){
scanf("%d%d%d",&flag,&x,&y);
if(flag==1) add(x,y,0),add(y,x,0);
else if(flag==2) add(x,y,1);
else if(flag==3) add(y,x,0);
else if(flag==4) add(y,x,1);
else if(flag==5) add(x,y,0);
}
for(register int i=n;i>=1;--i) {//玄学连边
add(0,i,1);
dis[i]=-inf;
}
if(!SPFA()) puts("-1");
else {
for(int i=1;i<=n;++i) ans+=dis[i];
printf("%lld",ans);
}
return 0;
}