差分约束的学习

来源:互联网 发布:淘宝店家不点发货 编辑:程序博客网 时间:2024/05/17 06:54

http://www.cnblogs.com/void/archive/2011/08/26/2153928.html很好的概述

实际上就是,这个系统通过,建图找最短路来解;

几种情况

1: x-y<=b约束时,直接addedge(a,b,c);

2: x-y>=b约束时,added(b,a,-1);

实际上,其他的不用管,只要把样式化为x-y=c的样式就可以,别的根本不用管,建完图套最短路即可

自我感觉,先判断两个数 a 和b的大小关系,列出关系式,再转化为标准的样式,然后建图,对了,如果找最大,那么 最短路 +"<=" 号

如果找最小, 最长路 + ">="号

1. 如果要求最大值想办法把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x权值为k的边,变得时候注意 x-y<k =>   x-y<=k-1

   如果要求最小值的话,变为x-y>=k的标准形式,然后建立一条从y到x的k边,求出最长路径即可(即如果最小值,改为>=)然后套模版

2.如果权值为正,用dj,spfa,bellman都可以,如果为负不能用dj,并且需要判断是否有负环,有的话就不存在

3:如果两个点相同,那么互相连0边即可。a-b<=0 && b-a<=0


然后最短路

模版题poj3159

#include<cstdio>#include<algorithm>#include<string>#include<cstring>#include<cmath>#include<iostream>#include<stack>using namespace std;const int inf=0x3f3f3f3f;struct{int pre,v,c;} edge[150009]; int n,m,k,head[100009],dist[100009];void addedge(int u,int v,int c){k++;edge[k].c=c;edge[k].v=v;edge[k].pre=head[u];head[u]=k;}bool b[100009]={false};int main(){scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);addedge(a,b,c);}//直接建图memset(dist,inf,sizeof(dist));//最短路的题,初始值都要设成inf,别忘了dist[1]=0;stack<int> s;s.push(1);b[1]=true;while (!s.empty()){int r=s.top();s.pop();for (int i=head[r];i;i=edge[i].pre){int vv=edge[i].v,cc=edge[i].c;if (dist[vv]>dist[r]+cc){dist[vv]=dist[r]+cc;if (!b[vv]) s.push(vv),b[vv]=true;}}b[r]=false;}//用的spfa,事实证明,spfa可以用栈实现printf("%d",dist[n]);return 0;}

scoi2011 bzoj 2330

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

两个注意事项,要求都要分到糖果就是,每一个人至少分到一个糖果。

至少需要多少糖果,就是希望每一个孩子分到的糖果尽量少还要满足要求,实际上就是求最小值,那么我们把式子转化为>=号,并且跑最长路即可


(稍微复杂一点,有几种情况需要判断,并且他问总共的最少糖果数,把单人的最少数量都加起来成和即可,还有别忘建一个超级源,dist【i】是和原点的距离,即最少需要的糖果数,因为,每一个人都要有糖,初始到超级源的距离就为1,因为1就已经是最少了)



这题很坑,需要加边从n往1加。

#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<queue>using namespace std;const int inf=0x3f3f3f3f;const int N=120005;int n,k;int head[N],dis[N],tot,tt[N];struct aa{int to,pre,dis;}edge[N*4];void addedge(int x,int y,int z){edge[++tot].to=y;edge[tot].dis=z;edge[tot].pre=head[x];head[x]=tot;}bool b[N];bool spfa(){dis[0]=0;b[0]=true;queue<int> q;q.push(0);while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=edge[i].pre)if (dis[edge[i].to]<dis[u]+edge[i].dis){int v=edge[i].to;dis[v]=dis[u]+edge[i].dis;tt[v]++;if (tt[v]==n) return false;//判环放在外面,只需用判定<strong>是否松弛n次</strong>就好,只要松弛n次,就可以判定有负(正)环!!if (!b[v]) {b[v]=true;q.push(v);}}b[u]=false;}return true;}int main(){scanf("%d%d",&n,&k);int A,B,op;while (k--){scanf("%d%d%d",&op,&A,&B);switch(op){case 1:addedge(A,B,0);addedge(B,A,0);break;case 2:addedge(A,B,1);if (A==B) {printf("-1");return 0;}break;case 3:addedge(B,A,0);break;case 4:addedge(B,A,1);if (A==B) {printf("-1");return 0;}break;case 5:addedge(A,B,0);break;}}for (int i=n;i>=1;i--) addedge(0,i,1);if (!spfa()) {printf("-1");return 0;}long long ans=0;for (int i=1;i<=n;i++) ans+=dis[i];printf("%lld",ans);return 0;}






1 0