如果一个系统由 n 个变量和 m 个约束条件组成,形成 m 个形如 ai - aj ≤ k 的不等式(i , j ∈ [1,n], k 为常数),则称其为差分约束
源点需要满足的条件: 从源点出发,一定可以走到所有的边
否则 用单源最短路做的话 有一条边走不到 则该边对应的不等式就无法满足
把每个x[i] ≤ x[j] + C[k]不等式转化为一条从 x[j] 走到 x[i] 长度为 C[k] 的边
然后在这个图上找一个超级源点,使得该源点一定可以遍历到所有边
从源点求一遍单源最短路
3.1假如存在负环
x[2] ≤ x[1] + c[1]
…
x[k] ≤ x[k-1] + c[k-1]
x[1] ≤ x[k] + c[k]
对第一个不等式用后面的不等式一直做松弛
x[2] ≤ x[1]+c[1]
≤ x[k] + c[k] + c[1]
≤ x[k-1] + c[k-1] + c[k] + c[1]
…
≤ x[2] + c[2] +…+ c[k-1] + c[k] + c[1]
≤ x[2] + (小于零的Σc[i])
x[2] < x[2]
矛盾
得出结论:不等式无解 即存在负环
4.求完单源最短路之后
存在负环 => 不等式无解
没有负环 => 求完之后一定是满足这个不等式的 <=> 即一个可行解
结论 : 如果求的是最小值,则应该求最长路,如果求的是最大值,则应该求最短路
问题 : 如何转化 x[i] ≤ c (其中 c 是一个常数) 这类的不等式
方法 : 建立一个超级源点, 0 号点 x[0] ,然后建立 0→i 长度是 c 的边即可
x[i] ≤ c <=> x[i] ≤ x[0] + c = 0 + c
以求 x[i] 的最大值为例:所有从 x[i] 出发,构成的不等式链
x[i] ≤ x[j] + c[1] ≤ x[k] + c[2] + c[1] ≤⋅⋅⋅≤ x[0] + c[1] + c[2] +⋅⋅⋅+ c[m] (x0=0)
所计算出的上界,最终 x[i] 的最大值 = 所有上界的最小值
那么求x[i]最大值
求所有上界的最小值
求所有从 0→i 的路径和的最小值
最短路求 dist[i]
题目概括
幼儿园里有 N 个小朋友,老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。
但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, 老师需要满足小朋友们的 K 个要求。
幼儿园的糖果总是有限的,老师想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
输入
输入的第一行是两个整数 N,K。
接下来 K 行,表示分配糖果时需要满足的关系,每行 3 个数字 X,A,B。
如果 X=1.表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多。
如果 X=2,表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果。
如果 X=3,表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果。
如果 X=4,表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果。
如果 X=5,表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果。
小朋友编号从 1 到 N。
输出
输出一行,表示老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 −1。
由题我们可以转换成不等式
每个人都能够分到糖果所以可以得到 x ≥ 1
x ≥ x0 + 1 可以设源点 x0 = 0
代码
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=1e5+10,M=N*3;
int n,k;
int e[M],h[N],ne[M],w[M],idx;
int q[N],dist[N],cnt[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
int hh=0,tt=1;
memset(dist,-0x3f,sizeof dist);
q[0]=0;
dist[0]=0;
st[0]=true;
while(hh!=tt)
{
int t=q[--tt];
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]<dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n+1) return false;
if(!st[j])
{
q[tt++]=j;
st[j]=true;
}
}
}
}
return true;
}
int main()
{
cin>>n>>k;
memset(h,-1,sizeof h);
while(k--)
{
int a,b,x;
cin>>x>>a>>b;
if(x==1) add(a,b,0),add(b,a,0);
else if(x==2) add(a,b,1);
else if(x==3) add(b,a,0);
else if(x==4) add(b,a,1);
else add(a,b,0);
}
for(int i=1;i<=n;i++) add(0,i,1);
if(!spfa()) puts("-1");
else
{
LL res=0;
for(int i=1;i<=n;i++) res+=dist[i];
cout<<res<<endl;
}
return 0;
}