如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
——百度百科
如下列的不等式组
x1-x5≤-1
x2-x5≤1
x3-x1≤5
x4-x1≤4
x4-x3≤-1
x5-x3≤-3
x5-x4≤-3
比如1式 x1-x5≤-1,其中一个未知数x1与x5的差小于等于-1,就相当于设两个未知数x,y差为某一常数,由这些不等式构成的不等式方程组为差分约束系统。
关于洛谷一道蓝题。
P1993 小K的农场
但因为在另一篇题解中写过了,所以不多做阐述,解题看好差分约束条件就行了。
小K的农场(差分约束)题解
然后是另外两道题
Description
虽然蒜头君并没有多少钱,但是蒜头君办了很多张银行卡,共有 n 张,以至于他自己都忘记了每张银行卡里有多少钱了。他只记得一些含糊的信息,这些信息主要以下列三种形式描述:
银行卡 a 比银行卡 b 至少多 c 元。
银行卡 a 比银行卡 b 至多多 c 元。
银行卡 a 和银行卡 c 里的存款一样多。
但是由于蒜头君的记忆有些差,他想知道是否存在一种情况,使得银行卡的存款情况和他记忆中的所有信息吻合。
Input
第一行输入两个整数 n 和 m,分别表示银行卡数目和蒜头君记忆中的信息的数目。(1≤n,m≤10000)
接下来 m 行:
如果每行第一个数是 1,接下来有三个整数 a,b,c,表示银行卡 a 比银行卡 b 至少多 c元。
如果每行第一个数是 2,接下来有三个整数 a,b,c,表示银行卡 a 比银行卡 b 至多多 c元。
如果每行第一个数是 3,接下来有两个整数 a,b,表示银行卡 a 和 b 里的存款一样多。(1≤n,m,a,b,c≤10000)
Output
如果存在某种情况与蒜头君的记忆吻合,输出Yes,否则输出No。
Sample Input 1
3 3
3 1 2
1 1 3 1
2 2 3 2
Sample Output 1
Yes
很明显,题目中出现了几个约束条件:
银行卡 a 比银行卡 b 至少多 c 元。
银行卡 a 比银行卡 b 至多多 c 元。
银行卡 a 和银行卡 c 里的存款一样多。
转化为不等式方程组:
a-b>=c
a-b<=c
a=c
找到了解题的关键,然后将差分约束转化为最短路求解 。
#include
using namespace std;
const int maxn=10100;
const int inf=0x3f3f3f3f;
int n,m;
struct node{
int v,w;
node(){ }
node(int _v,int _w){
v=_v;
w=_w;
}
};
vector g[maxn];
int dst[maxn];
queue qu;
bool inq[maxn];
int cnt[maxn];
int add(int u,int v,int w){
g[u].push_back(node(v,w));
// g[v].push_back(node());
}
int spfa(int u){
memset(inq,0,sizeof inq);
memset(dst,inf,sizeof dst);
memset(cnt,0,sizeof cnt);
dst[u]=0;
qu.push(u);
inq[u]=1;
cnt[u]=1;
while(!qu.empty()){
u=qu.front();
qu.pop();
inq[u]=0;
for(int i=0;idst[u]+w){
dst[v]=dst[u]+w;
if(!inq[v]){
qu.push(v);
inq[v]=1;
cnt[v]++;
if(cnt[v]>n+1){
return 0;
}
}
}
}
}
return 1;
}
int main(){
cin >> n >> m;
for(int i=0;i> d;
if(d==1){
cin >>a>>b>>c;
g[a].push_back(node(b,-c));
}else if(d==2){
cin >>a>>b>>c;
g[b].push_back(node(a,-c));
}else{
cin >>a>>b;
g[a].push_back(node(b,0));
g[b].push_back(node(a,0));
}
}
for(int i=1;i<=n;i++){
add(0,i,0);
}
if(spfa(0)){
cout << "Yes"<
Description
蒜头君苦练厨艺,终于成为了某高档酒店的大厨。
每天上班,蒜头君会被要求做 n 份菜。既然是高档酒店,那么客人们当然是很讲究的,尤其对于上菜的时间有很多要求。客人们的要求被分成下列四种:
菜品 a 的上菜时间必须比菜品 b 的上菜时间早 d 分钟或者更早。
菜品 a 的上菜时间必须比菜品 b 的上菜时间迟 d 分钟或者更迟。
菜品 a 的上菜时间在 d 分钟以后(包含 d 分钟)。
菜品 a 的上菜时间在 d 分钟之前(包含 d 分钟)。
蒜头君的上班时间记为 0 分钟。为了节约时间,在满足客人们要求的情况下,蒜头君希望最后上的一道菜的时间尽可能的早。(每道菜的上菜时间必须不早于蒜头君的上班时间)
Input
第一行输入一个整数 n,表示一共需要上 n 道菜。
第二行输入一个整数 m,表示客人们的要求数量。
接下里 m 行,每行先输入一个整数 op。
如果 op=1,表示描述里的第 1 种要求,后面跟着三个整数 a,b,d。
如果 op=2,表示描述里的第 2 种要求,后面跟着三个整数 a,b,d。
如果 op=3,表示描述里的第 3 种要求,后面跟着两个整数 a,d。
如果 op=4,表示描述里的第 4 种要求,后面跟着两个整数 a,d。
Output
如果蒜头君能满足客人们的要求,输出最后一道菜的上菜时间;否则输出一行 'I can't'。
数据范围和约定
对于所有的数据:1≤n,m≤20000,1≤∣d∣≤10000 ,1≤a,b≤n,a≠b。
样例解释 1
1,2,3 的上菜时间分别为 0,2,12,这样能满足输入客人们的所有要求,并且时间最短。
Sample Input 1
3
5
2 3 2 10
2 2 1 2
2 3 2 5
1 2 3 7
3 3 9
Sample Output 1
12
Sample Input 2
3
4
3 1 3
2 3 1 9
2 1 3 -1
1 1 2 5
Sample Output 2
I can't
Sample Input 3
17
20
2 6 3 -21
1 8 2 54
3 7 -95
4 11 44
1 5 15 40
3 9 1
3 3 30
3 8 23
2 9 12 -15
4 13 61
2 3 7 31
1 5 10 -15
2 16 1 43
2 12 3 -79
2 14 16 -51
3 6 48
4 7 0
2 10 11 -59
2 12 17 -29
3 4 10
Sample Output 3
77
与蒜头君的银行卡差不多,都是找到差分约束条件:
菜品 a 的上菜时间必须比菜品 b 的上菜时间早 d 分钟或者更早。
菜品 a 的上菜时间必须比菜品 b 的上菜时间迟 d 分钟或者更迟。
菜品 a 的上菜时间在 d 分钟以后(包含 d 分钟)。
菜品 a 的上菜时间在 d 分钟之前(包含 d 分钟)。
#include
using namespace std;
const int maxn=20010;
int n,m;
struct node{
int v,w;
node(){ }
node(int _v,int _w){
v=_v;
w=_w;
}
};
vector g[maxn];
int dst[maxn];
queue qu;
bool inq[maxn];
int cnt[maxn];
int flag;
int add(int u,int v,int w){
g[u].push_back(node(v,w));
// g[v].push_back(node());
}
void spfa(int u){
memset(inq,0,sizeof inq);
memset(dst,0x80,sizeof dst);
memset(cnt,0,sizeof cnt);
dst[u]=0;
qu.push(u);
inq[u]=1;
cnt[u]=1;
while(!qu.empty()){
u=qu.front();
qu.pop();
inq[u]=0;
for(int i=0;in+1){
return;
}
if(cnt[v]==n+1){
flag=1;
}
}
}
}
}
return;
}
int main(){
cin >> n >> m;
for(int i=0;i> d;
if(d==1){
cin >>a>>b>>c;
g[a].push_back(node(b,c));
}else if(d==2){
cin >>a>>b>>c;
g[b].push_back(node(a,c));
}else if(d==3){
cin >>a>>b;
g[0].push_back(node(a,b));
}else{
cin >>a>>b;
g[0].push_back(node(0,-b));
}
}
for(int i=1;i<=n;i++){
add(0,i,0);
}
int ans=0;
spfa(0);
if(flag){
cout<<"I can't";
return 0;
}
for(int i=1;i<=n;i++){
ans=max(ans,dst[i]);
}
cout << ans;
return 0;
}