poj 1201 Intervals 差分约束系统

题意:有一个序列,题目用n个整数组合 [ai,bi,ci]来描述它,[ai,bi,ci]表示在该序列中处于[ai,bi]这个区间的整数至少有ci个。如果存在这样的序列,请求出满足题目要求的最短的序列长度是多少。如果不存在则输出-1。


分析:第一次写差分约束系统,还是不是很熟。有一篇别人写的文章,已经很详细了,我就不多说了(笔者很懒的)

差分约数系统的含义,其实就是如果有n个变量在m个形如aj-ai>=bk条件下,求解的此不等式的方法。

这种不等式的解法其实就是转化为图论的最小路的算法求解的。我们将上面的不等式边形后得到aj-bk>=ai正好就可以看做是从aj到ai权值是-bk的一条路径最短的边。这样一来,只要依照题目的条件写出一系列这样的不等式,也就是相当于按照题意增加了一些合法的边,也就完全转化为了最短路的算法。

   再看这道题,题目说[ai, bi]区间内和点集Z至少有ci个共同元素,那也就是说如果我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边,权值为ci,但是这远远不够,因为有很多点依然没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时,我们再看看Si的定义,也不难写出0<=Si - Si-1<=1的限制条件,虽然看上去是没有什么意义的条件,但是如果你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。

我们将上面的限制条件写为同意的形式:

Sbi - Sai >= ci

Si - Si-1 >= 0

Si-1 - Si >= -1

这样一来就构造出了三种权值的边,而最短路自然也就没问题了。

但要注意的是,由于查分约束系统里常常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。


代码:

var

  n,e,s,t:longint;
  d,last:array[1..60000] of longint;
  side:array[1..200000] of record
    x,y,z,next:longint;
  end;

procedure add(x,y,z:longint);
begin
  inc(e);
  side[e].x:=x; side[e].y:=y; side[e].z:=z;
  side[e].next:=last[x]; last[x]:=e;
end;

procedure init;
var
  i,x,y,z:longint;
begin
  readln(n);
  s:=maxlongint;
  t:=0;
  for i:=1 to n do
  begin
    readln(x,y,z);
    if x<s then s:=x;
    if y+1>t then t:=y+1;
    add(y+1,x,-z);
  end;
  for i:=s to t-1 do
  begin
    add(i+1,i,0);
    add(i,i+1,1);
  end;
end;

procedure bellman;
var
  flag:boolean;
  i:longint;
begin
  while true do
  begin
    flag:=true;
    for i:=1 to e do
      with side[i] do
        if d[x]+z<d[y] then
        begin
          d[y]:=d[x]+z;
          flag:=false;
        end;
    if flag then break;
  end;
  writeln(d[t]-d[s]);
end;

begin
  init;
  bellman;
end.


你可能感兴趣的:(poj 1201 Intervals 差分约束系统)