您的位置:首页 > 其它

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个球。放法满足



(0<i≤m)约束,其中



表示区间



最多可放



个球,求这n个盒子最多可放多少个球。[1] 

令前k个盒子放的数目为



,则有







(1 ≤ i ≤ n ),



(1 ≤ i ≤ m)。以此约束条件用如上算法给出最短路径序列



,由定理知



是合法的放法,且



为最大值。

差分约束系统的确立要根据自己确定的约束条件,从约束点走向被约束点

连边一般有两种方法,第一种是连边后求最长路的方法,第二种是连边后求最短路的方法。

Poj 1201 http://poj.org/problem?id=1201
Intervals

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 23195 Accepted: 8761
Description

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息