【学习】差分约束

今天%你赛考了差分约束相关,于是发现又有忘了的东西,复习

0x00 差分约束

差分约束是求解N元一次特殊不等式组的一种方法。差分约束系统包含$N$个变量和$M$个约束条件,每个约束条件都是一个关于其中两个变量的一个一次不等式

,每个不等式形如$x[i]-x[j]≤a[k]$,$x[i],x[j]$为变量,$a[k]$为常数。

引理:若${Xi}$为差分约束系统的一组解,$∆$为任意常数,那么${Xi+∆}$也是一组解。

0x10 最短路

差分约束系统中的每个不等式都与最短路中的三角形不等式$dis[v]≤dis[u]+e(u,v)$,即$dis[v]-dis[u]≤e(u,v)$形似。

所以我们把每个变量$x_i$看做有向图中的一个点i,对于每个不等式$x[i]-x[j]≤a[k]$,即$x[i]≤x[j]+a[k]$,可看做从$j$向$i$连一条有向边,边权为$a[k]$。

另设源点$S$,由$S$向所有点建边权为$a$的边,求完最短路后的$dis[i]$即为$X[i]$的一组解。

如果有负环,说明无解。

如果想求最小值,将不等式*=-1,则≤变为≥,用最长路解决即可,如果有正环则无解。

0x11 负环问题

如何判断是否出现负环?

①记录每个点的入队次数,若某个点入队超过n次说明有负环。

②记录更新到每个点的最短路长度,如果dis[x]+e(x,y)更新了y,那么len[y]=len[x]+1,若长度超过n说明有负环。

被学长推荐第二种

0x20 例题

poj 3169

 

 

 

 

Luogu P1993 小k的农场

裸的板板

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5 const int inf=1e9+7;
 6 const int maxn=1e5+10;
 7 inline int read(){
 8     int x=0,f=1;
 9     char c=getchar();
10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
11     while(c>='0'&&c<='9'){x=(x*10)+c-'0';c=getchar();}
12     return x*f;
13 }
14 struct edge{
15     int to,nxt,w;
16 }e[maxn*2];
17 int head[maxn],cnt,vis[maxn],dis[maxn];
18 inline void add(int from,int to,int w){
19     e[++cnt].to=to;e[cnt].w=w;
20     e[cnt].nxt=head[from];head[from]=cnt;
21 }
22 bool spfa(int x){
23     vis[x]=1;
24     for(int i=head[x];i;i=e[i].nxt){
25         int y=e[i].to;
26         if(dis[y]<dis[x]+e[i].w){
27             dis[y]=dis[x]+e[i].w;
28             if(vis[y])return 0;
29             if(!spfa(y))return 0;
30         }
31     }
32     vis[x]=0;
33     return 1;
34 }
35 int n,m;
36 int main(){
37     n=read();m=read();
38     for(int i=1;i<=m;i++){
39         int x,a,b,c;
40         x=read();
41         if(x==1){
42             a=read();b=read();c=read();
43             add(b,a,c);
44         }
45         if(x==2){
46             a=read();b=read();c=read();
47             add(a,b,-c);
48         }
49         if(x==3){
50             a=read();b=read();
51             add(a,b,0);add(b,a,0);
52         }
53     }
54     for(int i=1;i<=n;i++){
55         add(0,i,0);
56         dis[i]=-inf;
57     }
58     if(!spfa(0))puts("No");
59     else puts("Yes");
60     return 0;
61 }
62 }
63 signed main(){
64   gengyf::main();
65   return 0;
66 }
View Code

 

Luogu P3275 [SCOI 2011]糖果

题解  (再次不要脸行为)

 

posted @ 2019-10-04 19:29  喵の耳  阅读(199)  评论(0编辑  收藏  举报