您的位置:首页 > 其它

poj1716 差分约束系统

2012-04-11 11:17 281 查看
CEOI的题,很经典!

对于区间问题,思路很多,但如果条件都是关于不等式的,那么就自然而然的联想到差分约束系统。

一看到区间,我就会联想到前缀和,而这道题正好用上了。

令sum[i]为从0--i选取到集合的个数的前缀和,则有题目条件可得:

对于区间[ai,bi],sum[bi]-sum[ai-1]>=2;

隐含条件:0<=sum[i+1]-sum[i]<=1;(很重要!)

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

  例:d[x]-d[y]>=Z

  如果想连边后求最长路 那么将不等式变形为这种形式 d[x]>=d[y]+z y---x连一条权值为z的边

求最短路则变形成d[y]<=d[x]-z x---y连一条权值为-z的边。

在差分约束系统中如果题目要求是求最小值,就将约束条件转化为">="形式,然后用spfa算法求解约束图的最长路径,如果题目要求的是最大值,就将约束条件转化为"<="形式,然后用spfa算法求解约束图的最短路径.(为什么?值得思考,有助于理解)

#include <iostream>
#include <queue>
using namespace std;

const int maxn=10005,maxm=40005,oo=9999999;
struct edge
{
int y,w,next;
}e[maxm];
int h[maxn],d[maxn];
bool v[maxn];
int n,m,tot=0;

void ins(int x,int y,int w)
{
e[++tot].y=y;e[tot].w=w;
e[tot].next=h[x];h[x]=tot;
}

int spfa()
{
int i,x,y;
for (i=0;i<=m;i++)
d[i]=-oo,v[i]=false;
d[0]=0;
queue<int> q;
q.push(0);v[0]=true;
while (!q.empty())
{
x=q.front();
for (i=h[x],y=e[i].y;i;i=e[i].next,y=e[i].y)
if (d[x]+e[i].w>d[y])
{
d[y]=d[x]+e[i].w;
if (!v[y])
{
q.push(y);
v[y]=true;
}
}
q.pop();
v[x]=false;
}
return d[m];
}

int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int a,b,i;
cin >> n;
for (i=0;i<n;i++)
{
cin >> a >> b;
if (b+1>m) m=b+1;
ins(a,b+1,2);
}
for (i=0;i<m;i++)
{
ins(i+1,i,-1);
ins(i,i+1,0);
}
cout << spfa();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: