差分约束系统详解(hdu1531 King为例)
2014-09-02 09:31
120 查看
嗯,这两天用空闲时间把差分约束系统学习了一下。话说暑假已经快结束了,在忙碌的时候,依然悠哉悠哉地学算法真的好吗。。。算了,学都已经学了,就把它放到网上作纪念吧(才不是强迫症呢,哼!)。因为是刚学的,所以有很多地方可能理解不当,希望大神们多加指教。
差分约束系统,就是将不等式的约束问题,抽象成最短路问题的一种方法,属于线性规划的一种。所以在此之前至少要熟练掌握Bellman-ford算法或者spfa算法的其中一种。Dijkstra是不行的,因为要处理负权边的问题。
首先我们先看看如何把不等式的约束问题转化为图论的最短路问题。假设有这样的约束条件:S[3]-S[0]<=k1, S[5]-S[3]<=k2,那么两式相加,则可以得出S[5]-S[0]<=k1+k2。可以抽象成,从节点0到3的距离为k1,从节点3到节点5的距离为k2.因为要满足所有的约束条件,对于<=这个关系,我们只需要求出0到5的最短路,最短路的长度,就是S[0]-S[5]的最大值。如果是>=这个关系,则需要求出最长路,最长路的长度,就是S[5]-S[0]的最小值。对于任意的S[i]-S[j]<=ki也可以根据上述条件很轻松地建图。如果不等式的关系不一致怎么办?比如S[i]-S[j]>=k1,
S[k]-S[j]<=k2.那么可以对于其中的一个不等式,两边同时乘以-1,可以得到S[j]-S[k]>=-k2,然后建图求解。
另外,不等式除了有一个解的情况,还有无数个解的情况和无解的情况,这又该如何判断呢?这里,在下就直接说方法了,不加证明了(拿特殊值代入法也能帮助理解)。当图中存在负环的时候,无解。当最后一个节点没有被更新的时候,有无穷多个解。
差分约束系统介绍完了,下面我们来看例题hdu1531.
hdu1531这一题,赤裸裸的差分约束系统的题目。就是国王给出一堆不等式,然后判断这个不等式所满足的数列是否存在,如果存在则输出lamentable king,如果不存在,则输出successful conspiracy。好的,下面来说明这道题。
因为这道题没有让你输出解,只让你输出是否有解,题目就变得更加简单了。设那个数列a1+a2+a3+...+an=Sn可以获得题目上的条件有两种可能,①S[si+ni]-S[si-1]>ki,②S[si+ni]-S[si-1]<ki。因为是<和>符号,我们需要把它换成>=和<=,怎么办呢?直接对于ki操作即可,变成>=ki+1,<=ki-1。最后变形完成可得:①S[si-1]-S[si+ni]<=-ki-1,②S[si+ni]-S[si-1]<=ki-1。然后直接建图,从0到n过一遍spfa或者bellman-ford就可以了,如果有负环,则输出successful
conspiracy,如果没有则输出lamentable king。但是需要注意的是,要使整个图联通才可以,所以将0节点设为虚点,我们在这里叫他超级节点。这个节点与所有点连通,权值为小于dist的初值的无穷大。我这里做的是求最短路。还有一点需要注意的是,因为是从0到n所以有n+1个节点,所以入队次数大于n+1时,才能被判断是负环,也算是一个小细节了,下面上代码:
代码君:
差分约束系统,就是将不等式的约束问题,抽象成最短路问题的一种方法,属于线性规划的一种。所以在此之前至少要熟练掌握Bellman-ford算法或者spfa算法的其中一种。Dijkstra是不行的,因为要处理负权边的问题。
首先我们先看看如何把不等式的约束问题转化为图论的最短路问题。假设有这样的约束条件:S[3]-S[0]<=k1, S[5]-S[3]<=k2,那么两式相加,则可以得出S[5]-S[0]<=k1+k2。可以抽象成,从节点0到3的距离为k1,从节点3到节点5的距离为k2.因为要满足所有的约束条件,对于<=这个关系,我们只需要求出0到5的最短路,最短路的长度,就是S[0]-S[5]的最大值。如果是>=这个关系,则需要求出最长路,最长路的长度,就是S[5]-S[0]的最小值。对于任意的S[i]-S[j]<=ki也可以根据上述条件很轻松地建图。如果不等式的关系不一致怎么办?比如S[i]-S[j]>=k1,
S[k]-S[j]<=k2.那么可以对于其中的一个不等式,两边同时乘以-1,可以得到S[j]-S[k]>=-k2,然后建图求解。
另外,不等式除了有一个解的情况,还有无数个解的情况和无解的情况,这又该如何判断呢?这里,在下就直接说方法了,不加证明了(拿特殊值代入法也能帮助理解)。当图中存在负环的时候,无解。当最后一个节点没有被更新的时候,有无穷多个解。
差分约束系统介绍完了,下面我们来看例题hdu1531.
hdu1531这一题,赤裸裸的差分约束系统的题目。就是国王给出一堆不等式,然后判断这个不等式所满足的数列是否存在,如果存在则输出lamentable king,如果不存在,则输出successful conspiracy。好的,下面来说明这道题。
因为这道题没有让你输出解,只让你输出是否有解,题目就变得更加简单了。设那个数列a1+a2+a3+...+an=Sn可以获得题目上的条件有两种可能,①S[si+ni]-S[si-1]>ki,②S[si+ni]-S[si-1]<ki。因为是<和>符号,我们需要把它换成>=和<=,怎么办呢?直接对于ki操作即可,变成>=ki+1,<=ki-1。最后变形完成可得:①S[si-1]-S[si+ni]<=-ki-1,②S[si+ni]-S[si-1]<=ki-1。然后直接建图,从0到n过一遍spfa或者bellman-ford就可以了,如果有负环,则输出successful
conspiracy,如果没有则输出lamentable king。但是需要注意的是,要使整个图联通才可以,所以将0节点设为虚点,我们在这里叫他超级节点。这个节点与所有点连通,权值为小于dist的初值的无穷大。我这里做的是求最短路。还有一点需要注意的是,因为是从0到n所以有n+1个节点,所以入队次数大于n+1时,才能被判断是负环,也算是一个小细节了,下面上代码:
代码君:
#include <cstdio> #include <algorithm> #include <string> #include <cstring> using namespace std; typedef struct { int x,y,z; }atp; atp line[220]; int s[110],nn[110],kk[110],found[110],dist[110],hash[110],flag,n,m,d[5000]; char o[110][110]; bool cmp(atp a,atp b) { return (a.x<b.x); } void spfa() { int f,r,vis[110],i; f=1;r=1; memset(vis,0,sizeof(vis)); d[f]=0; dist[0]=0; vis[0]=1; while(f<=r) { for(i=found[d[f]];line[i].x==d[f]&&i<=m+n;i++) { if(dist[line[i].y]>dist[line[i].x]+line[i].z) { dist[line[i].y]=dist[line[i].x]+line[i].z; if(!vis[line[i].y]) { if(hash[line[i].y]>n+1) //要注意是>n+1而不是n { flag=1; return; } r++; vis[line[i].y]=1; d[r]=line[i].y; hash[line[i].y]++; } } } vis[d[f]]=0; f++; } } int main() { int i,j,k; while(scanf("%d",&n)!=EOF) { if(n==0) break; scanf("%d",&m); for(i=1;i<=m;i++) scanf("%d%d%s%d",&s[i],&nn[i],o[i],&kk[i]); k=0; for(i=m+1;i<=m+n+1;i++) { line[i].x=0; k++; line[i].y=k; line[i].z=10000000; } for(i=1;i<=m;i++) { if(strcmp(o[i],"gt")==0) { line[i].x=s[i]+nn[i]; line[i].y=s[i]-1; line[i].z=-kk[i]-1; } if(strcmp(o[i],"lt")==0) { line[i].x=s[i]-1; line[i].y=s[i]+nn[i]; line[i].z=kk[i]-1; } } k=1; for(i=0;i<=100;i++) dist[i]=2147483647; sort(line+1,line+m+n+1,cmp); line[0].x=-1; for(i=1;i<=m+n;i++) { if(line[i].x!=line[i-1].x) found[line[i].x]=i; } memset(hash,0,sizeof(hash)); flag=0; spfa(); if(flag==1) printf("successful conspiracy\n"); else printf("lamentable kingdom\n"); } return 0; }
相关文章推荐
- HDU1531 King 【差分约束系统】
- 差分约束系统详解
- <kingofark关于学习C++和编程的50个观点> 详解 - 预览版
- [poj 1364]King[差分约束详解(续篇)][超级源点][SPFA][Bellman-Ford]
- DOS常用命令详解(恢复系统用到的命令)by cubeking
- POJ 1364 King ( 差分约束系统 )
- [poj 1364]King[差分约束详解(续篇)][超级源点][SPFA][Bellman-Ford]
- UVa 515 King (差分约束系统)
- 差分约束系统详解
- UVa 515 King(差分约束系统)
- PKU 1364 KING【差分约束系统】
- POJ 1364 King (差分约束系统)
- mysql 数据表读锁机制详解 by cubeking
- [poj 1364]King[差分约束详解(续篇)][超级源点][SPFA][Bellman-Ford]
- King 差分约束系统
- POJ 1364 King(差分约束系统)
- poj 1364 King (差分约束系统)
- ZOJ1260 POJ1364 HDU1531 King
- UVa 515 King (差分约束系统)
- 差分约束系统详解