POJ1201 Intervals

题目的大意是给定若干(a,b,c)表示[a,b]之间有c个1,序列只能是0或者1,最后问在这些约束下,序列的最小长度。稍微变形就成了典型的差分约束问题,转化成S(b)-S(a)<=c这样的问题,然后用算导上的建模过程,a->b连条边,权值为c,因为这样的话,对于最后的dis(a)和dis(b),需要符合dis(b)<=dis(a)+w(a->b),也就是dis(b)-dis(a)<=w(a->b)。所以在加个虚拟的约束点后,点集v={v0,v1...vn}的解就是dis(0),dis(1)...dis(n){dis(i)表示建图后v0到vi的最短路},根据上述就能推出所对应的约束条件了。而这题就是求S(max)-S(min)的最小值,就是求Vmax到Vmin的最短距离,需要注意的是还有这样的约束条件0<=S(i+1)-S(i)<=1,这样同时也保证了图的连通性。对于POJ1364 King这题,是类似的,不过题目只给出"<"或者">",要转换,同时为保证连通性,可以这样处理,先将这n个点push到队列中,但这只算了虚节点的入队次数,但不管这些,入队n次以上,肯定是有负环的,可以反证。不过我后来加了个-1000<=S(i+1)-S(i)<=1000,这样一个条件,也AC,想法就是保证了它的连通性。

感谢:

http://www.cppblog.com/initiate/archive/2010/04/03/111530.html
http://blog.csdn.net/ChinaCzy/archive/2010/07/26/5767025.aspx

代码
#include <iostream>
#include
<vector>
#include
<queue>
using namespace std;

const int MAX = 50005;

struct NODE
{
int v, w;
NODE() {}
NODE(
int vv, int ww) : v(vv), w(ww) {}
};

vector
<vector<NODE> > mm;

int in[MAX];
int dis[MAX];

int spfa(int beg, int end)
{
memset(
in, 0, sizeof(in));
memset(dis,
-1, sizeof(dis));
queue
<int> Q;
in[beg] = 1;
dis[beg]
= 0;
Q.push(beg);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
in[u] = 0;
for(int i = 0; i < mm[u].size(); i++)
{
int v = mm[u][i].v;
int w = mm[u][i].w;
if(dis[u] + w > dis[v])
{
dis[v]
= dis[u] + w;
if(in[v] == 0) Q.push(v), in[v] = 1;
}
}
}
return dis[end];
}

int main()
{
int cnt;
mm.clear();
mm.resize(MAX);
scanf(
"%d", &cnt);
int minv = MAX, maxv = -1;
while(cnt--)
{
int a, b, c;
scanf(
"%d%d%d", &a, &b, &c);
b
++;
minv
= min(minv, a);
maxv
= max(maxv, b);
//s(b) - s(a) >= c
mm[b].push_back(NODE(a, c));
}
//0 <= s(i + 1) - s(i) <= 1

for(int i = minv; i <= maxv - 1; i++)
{
mm[i
+ 1].push_back(NODE(i, 0));
mm[i].push_back(NODE(i
+ 1, -1));
}

//必有解,无需判负环
printf("%d\n", spfa(maxv, minv));
}

 

posted @ 2010-08-08 20:36  litstrong  阅读(1331)  评论(0编辑  收藏  举报