Poj 1201 差分约束问题 详解
2015-07-27 13:30
495 查看
差分约束问题:
如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。
例:设有n个盒子标号为1...n,每个盒子最多放1个球。放法满足
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/9879be743ce7bdbefda9f3d5dd680972.jpg)
(0<i≤m)约束,其中
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/9879be743ce7bdbefda9f3d5dd680972.jpg)
表示区间
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/a32b55d4a3d0332854f94d5d3e2765cd.jpg)
最多可放
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/07697b6acd412174482b18500d7963b7.jpg)
个球,求这n个盒子最多可放多少个球。[1]
令前k个盒子放的数目为
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/cb64998b180669ba6ab8f9696e76b16e.jpg)
,则有
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/d0914bcb3964ea7d499f594e6fad5b79.jpg)
,
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/ff4b006e59b54466a3d282f9dffbe877.jpg)
(1 ≤ i ≤ n ),
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/e20d032f86e54cc494999a49b663cf7f.jpg)
(1 ≤ i ≤ m)。以此约束条件用如上算法给出最短路径序列
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/47e790ac0fe56f4e0ee4f78c7c0804ae.jpg)
,由定理知
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/47e790ac0fe56f4e0ee4f78c7c0804ae.jpg)
是合法的放法,且
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/e335447796049102f49350b962fd1803.jpg)
为最大值。
差分约束系统的确立要根据自己确定的约束条件,从约束点走向被约束点
连边一般有两种方法,第一种是连边后求最长路的方法,第二种是连边后求最短路的方法。
Poj 1201 http://poj.org/problem?id=1201
题目意思:
有n个[ai,bi]区间,以及对应一个ci值。求最小的集合Z,满足与[ai,bi]区间有ci个相同元素。
构建差分约束:dist[i]表示源点s到i的区间[s,i]与Z集合相同元素个数,那么满足:
dist[i]<=dist[i+1]<=dist[i]+1
&& dist[ai]+ci<=dist[bi+1]
(bi+1的原因是区间个数需要加1)
根据最短路不等式,若(a,b,c),即a到b有边权为c,那么dist[b]<=dist[a]+c
(a约束点,b被约束点)
如此,建求最短路图:(i+1,i,0),(i,i+1,1) && (bi+1,ai,-ci) 结果为最大点(约束点)到最小点(被约束点)的最短路。结果是负值需要取反。
建求最远路图:最远不等式,若(a,b,c),那么dist[b]>=dist[a]+c
建图:(i,i+1,0),(i+1,i,-1) && (ai,bi+1,ci)
结果为最小点(约束点)到最大点(被约束点)的最远路。结果为正值。
如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。
例:设有n个盒子标号为1...n,每个盒子最多放1个球。放法满足
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/9879be743ce7bdbefda9f3d5dd680972.jpg)
(0<i≤m)约束,其中
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/9879be743ce7bdbefda9f3d5dd680972.jpg)
表示区间
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/a32b55d4a3d0332854f94d5d3e2765cd.jpg)
最多可放
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/07697b6acd412174482b18500d7963b7.jpg)
个球,求这n个盒子最多可放多少个球。[1]
令前k个盒子放的数目为
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/cb64998b180669ba6ab8f9696e76b16e.jpg)
,则有
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/d0914bcb3964ea7d499f594e6fad5b79.jpg)
,
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/ff4b006e59b54466a3d282f9dffbe877.jpg)
(1 ≤ i ≤ n ),
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/e20d032f86e54cc494999a49b663cf7f.jpg)
(1 ≤ i ≤ m)。以此约束条件用如上算法给出最短路径序列
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/47e790ac0fe56f4e0ee4f78c7c0804ae.jpg)
,由定理知
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/47e790ac0fe56f4e0ee4f78c7c0804ae.jpg)
是合法的放法,且
![](https://oscdn.geek-share.com/Uploads/Images/Content/201910/24/e335447796049102f49350b962fd1803.jpg)
为最大值。
差分约束系统的确立要根据自己确定的约束条件,从约束点走向被约束点
连边一般有两种方法,第一种是连边后求最长路的方法,第二种是连边后求最短路的方法。
Poj 1201 http://poj.org/problem?id=1201
Intervals
You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a program that: reads the number of intervals, their end points and integers c1, ..., cn from the standard input, computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n, writes the answer to the standard output. Input The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1. Output The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each d2b1 i=1,2,...,n. Sample Input 5 3 7 3 8 10 3 6 8 1 1 3 1 10 11 1 Sample Output 6 Source Southwestern Europe 2002 |
有n个[ai,bi]区间,以及对应一个ci值。求最小的集合Z,满足与[ai,bi]区间有ci个相同元素。
构建差分约束:dist[i]表示源点s到i的区间[s,i]与Z集合相同元素个数,那么满足:
dist[i]<=dist[i+1]<=dist[i]+1
&& dist[ai]+ci<=dist[bi+1]
(bi+1的原因是区间个数需要加1)
根据最短路不等式,若(a,b,c),即a到b有边权为c,那么dist[b]<=dist[a]+c
(a约束点,b被约束点)
如此,建求最短路图:(i+1,i,0),(i,i+1,1) && (bi+1,ai,-ci) 结果为最大点(约束点)到最小点(被约束点)的最短路。结果是负值需要取反。
建求最远路图:最远不等式,若(a,b,c),那么dist[b]>=dist[a]+c
建图:(i,i+1,0),(i+1,i,-1) && (ai,bi+1,ci)
结果为最小点(约束点)到最大点(被约束点)的最远路。结果为正值。
//最短路求法,dist初始INF #include<iostream> #include<cstdio> #include<vector> #include<queue> using namespace std; #define INF 0x3fffffff struct node{ //容器做边表 int v,w; node(int v_=0,int w_=0):v(v_),w(w_){} }; vector <node> edge[50001]; int mark[50001];//spfa标记数组 int dist[50001];//距离数组 void spfa(int s,int e){//s到e的spfa queue <int> que; que.push(s); mark[s]=1; dist[s]=0; while(!que.empty()){ int u=que.front();que.pop(); mark[u]=0; //!!!! int len=edge[u].size(); for(int i=0;i<len;i++){ int v=edge[u][i].v; int w=edge[u][i].w; if(dist[v]>dist[u]+w){ dist[v]=dist[u]+w; if(mark[v]==0){//spfa重点 mark[v]=1; que.push(v); } } } } } int main(){ int n; while(~scanf("%d",&n)){ for(int i=0;i<=50000;i++){ edge[i].clear(); dist[i]=INF;//初始化 mark[i]=0; } int mi=INF,ma=-1; for(int i=0;i<n;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); edge[b+1].push_back(node(a,-c));//大点到小点的边 mi=min(mi,a); ma=max(ma,b+1); } for(int i=mi;i<ma;i++){//隐藏约束条件 edge[i].push_back(node(i+1,1)); edge[i+1].push_back(node(i,0)); } spfa(ma,mi);//最大点到最小点 printf("%d\n",-dist[mi]);//结果负值 } return 0; }
//最远路求法,dist初始-INF #include<iostream> #include<cstdio> #include<vector> #include<queue> using namespace std; #define INF 0x3fffffff int n; struct node { int v,w; node(int v_=0,int w_=0):v(v_),w(w_){} }; vector <node> edge[50001]; int dist[50001]; int mark[50001]; void spfa(int s,int e){ queue <int> que; que.push(s); mark[s]=1; dist[s]=0; while(!que.empty()){ int u=que.front();que.pop(); mark[u]=0; int len=edge[u].size(); for(int i=0;i<len;i++){ int v=edge[u][i].v; int w=edge[u][i].w; if(dist[v]<dist[u]+w){//不要等于!!!! dist[v]=dist[u]+w; if(mark[v]==0){ mark[v]=1; que.push(v); } } } } } int main(){ while(~scanf("%d",&n)){ for(int i=0;i<=50000;i++){ edge[i].clear(); mark[i]=0; dist[i]=-INF;//初始化 } int mi=50000+10,ma=-1; for(int i=0;i<n;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); edge[a].push_back(node(b+1,c)); mi=min(mi,a); ma=max(ma,b+1); } for(int i=mi;i<ma;i++){ edge[i].push_back(node(i+1,0)); edge[i+1].push_back(node(i,-1)); } spfa(mi,ma); printf("%d\n",dist[ma]); } return 0; }