POJ 1201 Intervals(差分约束)
http://poj.org/problem?id=1201
题意:有n个如下形式的条件:
ai bi ci,表示在区间[ai, bi]内至少要选择ci个整数点.
问你满足n个条件的情况下,最少需要选多少个点?
分析:
令s[x]表示从区间[0,x]中选择的整数点个数.那么对于条件[ai, bi]选数>=ci个,就是 s[bi]-s[ai-1]>=ci. 即s[ai-1]<=s[bi]+ (-ci)
假设有下面两个条件:
1 2 3 5 6 3, 那么我们自然得出了s[2]-s[0]>=3 且s[6]-s[4]>=3.
如果s[2]=3,s[0]=0,s[6]=3,s[4]=0 是满足上面不等式的.但是其实是不合题意的.因为s[4]必然要>=s[2]和s[0]的.所以我们需要把s的相对值也联系起来.
这样就需要添加下面的边. 假设我们令输入读取的区间最大值为max_v. 那么对于所有 0<i<=max_v的值来说,有
0<=s[i]-s[i-1]<=1 .转换一下即是: s[i]<=1+s[i-1] && s[i-1]<=0+s[i].
根据上面的分析,我们要建的有向图是一个具有max_v+1个点的图.其中的边有:
n条s[bi]-s[ai-1]>=ci条件构成的从bi到 (ai-1)的长-ci的边.
还有所有 0<i<=max_v的值构成的 i到i-1的长0的边和
i-1到i的长1的边.所以这样我们就形成了一个具有点[0,max_v]的有向图.在原图处理时,为了避免ai-1==-1,我们令所有ai与bi都自增了10.所以我们形成了一个具有点[9,max_v]的有向图(其实就是差分约束系统).我们的目标是令S[max_v]-S[9]的值最小.(切记这里不是仅使S[max_v]的值最小,因为我们这里只有从9
,10,11,…max_v 的值构成了一个差分约束系统.max_v的值和0号点的值是不在一个系统的. 0号点是超级源点,它的值与系统中其他点的值是无关的.)
然后我们上面已经知道了希望让系统中S[max_v]和S[9]的值差距尽量小.(构成差分约束系统时,1.如果在所有点外添加一个超级源0号点,并使得超级源到所有其他点的距离为0,那么最终求出的0号点到其他所有原始点的最短距离就是本系统的一个可行解,且可行解之间的差距最小.2.如果初始时不添加超级源,只是将原始点的初始距离设为INF,且令其中一个原始点的初始距离为0,然后求该点到其他所有点的最短距离,那么最短距离的集合就是一个可行解,且该可行解两两之间的差距最大.注意方案2只能在该问题一定存在解的时候即肯定不存在负权环的时候用.否则从1号点到其他点没有路,但是其他点的强连通分量中有负权环,这样根本探测不到错误)
所以我们需要采取方案1.
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn= 50000+10;
const int maxm=500000+10;
#define INF 1e9
struct Edge
{
int from,to,dist;
Edge(){}
Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
struct SPFA
{
int n,m;
int head[maxn],next[maxm];
Edge edges[maxm];
int d[maxn];
bool inq[maxn];
void init()
{
m=0;
memset(head,-1,sizeof(head));
}
void AddEdge(int from,int to,int dist)
{
edges[m]=Edge(from,to,dist);
next[m]=head[from];
head[from]=m++;
}
int spfa()
{
memset(inq,0,sizeof(inq));
for(int i=0;i<n;i++) d[i]= i==0?0:INF;
queue<int> Q;
Q.push(0);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=head[u];i!=-1;i=next[i])
{
Edge &e=edges[i];
if(d[e.to]>d[u]+e.dist)
{
d[e.to]=d[u]+e.dist;
if(!inq[e.to])
{
inq[e.to]=true;
Q.push(e.to);
}
}
}
}
return d[n-1]-d[9];
}
}SP;
int main()
{
int n,max_v=-1;
scanf("%d",&n);
SP.init();
while(n--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
b+=10,a+=10;//所有值都加10了,以免a-1成为-1
max_v=max(max_v,b);
SP.AddEdge(b,a-1,-c);
}
for(int i=10;i<=max_v;i++)//从该循环可看出,本差分约束的点编号为:[9,max_v](未包含超级源0号点)
{
SP.AddEdge(i,i-1,0);
SP.AddEdge(i-1,i,1);
SP.AddEdge(0,i,0);
}
SP.AddEdge(0,9,0);
SP.n=max_v+1;
printf("%d\n",SP.spfa());//注意最终结果是d[max_v]-d[9]的值,而不是d[max_v]的单独值
return 0;
}
AC代码: 为了验证0号超级源在差分约束系统之外,可以把上面的代码和下面的代码做个对比.
//AC代码2
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn= 50000+10;
const int maxm=500000+10;
#define INF 1e9
struct Edge
{
int from,to,dist;
Edge(){}
Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
struct SPFA
{
int n,m;
int head[maxn],next[maxm];
Edge edges[maxm];
int d[maxn];
bool inq[maxn];
void init()
{
m=0;
memset(head,-1,sizeof(head));
}
void AddEdge(int from,int to,int dist)
{
edges[m]=Edge(from,to,dist);
next[m]=head[from];
head[from]=m++;
}
int spfa()
{
memset(inq,0,sizeof(inq));
for(int i=0;i<n;i++) d[i]= i==0?0:INF;
queue<int> Q;
Q.push(0);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=head[u];i!=-1;i=next[i])
{
Edge &e=edges[i];
if(d[e.to]>d[u]+e.dist)
{
d[e.to]=d[u]+e.dist;
if(!inq[e.to])
{
inq[e.to]=true;
Q.push(e.to);
}
}
}
}
return d[n-1]-d[3];//修改111111111
}
}SP;
int main()
{
int n,max_v=-1;
scanf("%d",&n);
SP.init();
while(n--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
b+=4,a+=4;//所有值都加1了,以免a-1成为-1//修改22222222222
max_v=max(max_v,b);
SP.AddEdge(b,a-1,-c);
}
for(int i=4;i<=max_v;i++)//从该循环可看出,本差分约束的点编号为:[3,max_v](未包含超级源0号点)//修改333333
{
SP.AddEdge(i,i-1,0);
SP.AddEdge(i-1,i,1);
SP.AddEdge(0,i,0);
}
SP.AddEdge(0,3,0);//修改44444444444
SP.n=max_v+1;
printf("%d\n",SP.spfa());//注意最终结果是d[max_v]-d[9]的值,而不是d[max_v]的单独值
return 0;
}
分享到:
相关推荐
北大POJ1201-Intervals 解题报告+AC代码
POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类
北大POJ1716-Integer Intervals【Difference Constraints】 解题报告+AC代码
北大POJ2983-Is the Information Reliable【差分约束+优化Bellman】 解题报告+AC代码
poj分类poj分类poj分类poj分类
poj 百练 题目分类 poj 百练 题目分类
POJ题目分类POJ题目分类POJ题目分类
POJ题解及题目分类,共150道左右。C/C++
该文档对poj大部分题目进行了分类,有利于喜欢在poj刷题的朋友
解决算法问题 poj1082, poj1150, poj1180, poj1201, poj1222,代码完成所给题目要求。
pojACM题目分类,便于各类型同学分别做题有所参考
poj上的算法题目分类,对于大家想练习算法的同鞋可以参考一下,里面按类列出了各种算法的题号。
poj题目分类
poj800多道题目的详细分类,比较具体,比网上的好多了值得下载。
POJ题目分类,列出了所有的类目,里面写了一些很好的框架。
poj题目分类打包 acm北大的题库题目分类 来源网络 网络还有自己整理一部分。好久前的玩意了
poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题...
强大的poj分类 学做POJ必备 非最新,供参考
史上最全poj题目分类及原题 包括:基本算法:贪心、递归、递推、枚举;基本数据结构,链表、栈;动态规划;搜索;高级数据结构:二叉搜索树、线段树、树状数组;数学:数论
史上最全poj题目分类(159页).pdf