【差分约束】king(国王)解题报告 …

【差分约束】king(国王)

Time Limit:1000MS  Memory Limit:65536K
Total Submit:28 Accepted:15

Description

国王(king.pas/c/cpp)

【问题描述】

从前,在一个王国里有一个皇后,皇后期待有一个婴儿。皇后祈祷:“要是我的孩子是个儿子并且他一个健全的国王就好了。”九个月后孩子出生了,事实上,她生下了一个漂亮的儿子。
不幸的是,就像过去发生在王室家庭的情况一样,她的儿子有点弱智。经过多年的学习,他仅仅能够加减整数,并比较结果是否大于或小于一个给定的整数。此外,数字必须写在一个序列里,且他仅仅能够计算序列中连续子序列的和。
老国王对他儿子很不高兴。但是,他准备做好一切使他的儿子在他死后能治理王国。知道他儿子的技能后,他决定每一个国王必须决定的问题必须是一个有限整数序列的形式,且问题通过计算某一上限或下限开始的序列和得以解决。这样至少有一些希望,他的儿子将能够做出一些决定。
老国王去世后,年轻的国王开始统治。但很快,很多人对他的决定非常不满,并决定将他废黜。他们试图证明他的决定是错误的。
因此一些阴谋家呈现给年轻国王一堆问题。这些问题的形式是在序列S = {a1, a2, ..., an}中的一些子序列Si = {aSi, aSi+1, ..., aSi+ni}。国王想了一会儿,然后决定,他的给每个子序列Si一个整数限制,并宣布这些限制由他的决定。
过了一会儿,他意识到,他的一些决定是错误的。他不能撤销这些整数限制,但他试图拯救自己,所以他决定改动给定他的序列。他下令他的顾问,找一个序列S,将满足aSi + aSi+1 + ... + aSi+ni < ki或者aSi + aSi+1 + ... + aSi+ni > ki。帮助国王的顾问,编写一个程序,决定这样的序列存在与否。

Input

输入包括多块。
除了最后一块,每块第一行包括两个整数n,m,其中0 < n <= 100,表示序列S的长度;0 < m <= 100,表示Si的数量。接下来m行包括四个整数si, ni, oi, ki,其中oi代表运算符>(用gt表示)或<(用lt表示)。
最后的一块包括一个整数0。

Output

除了最后一块,每块输出一行,若序列存在,则输出lamentable kingdom;若序列不存在,则输出successful conspiracy。

Sample Input

4 2
1 2 gt 0
2 2 lt 2
1 2
1 0 gt 0
1 0 lt 0
0


Sample Output

lamentable kingdom
successful conspiracy

Hint

本题数据不完整,请在本系统测试通过后到 http://poj.org/problem?id=1364 提交完整测试!

Source

Central Europe 1997

 

 

差分约束系统的典型题。

题目中提到的序列,一开始还以为是有规律的,后来百度才知道

  数学上,序列是被排成一列的对象(或事件);这样,每个元素不是在其他元素之前,就是在其他元素之后。这里,元素之间的顺序非常重要。

 

 

Bellman-Ford算法,晕乎乎地就过了。

下面这个程序如果用{ }里面的语句,虽然也过了,但并不完全正确。。。。

我把0号节点作为添加的节点,并使其到i节点的距离w[0,i]或d[i]为零。

可是,如输入样例1
1 2 gt 0
在构图时 1-1=0  1+2=3

就会用到 0号 和 3号点

这样0号节点就出问题了。 

 

var
 c,cc:char;
 n,m,x,i,j,y,z:longint;
 w:array[0..100,0..100]of longint;
 a:array[1..100,1..2]of longint;
 d:array[0..100]of longint;

 

procedure work;
var
 i,j,pan:longint;
begin
 for i:=1 to 100 do d[i]:=0{maxlongint div 2};
 d[0]:=0;

 for i:=1 to n do
  for j:=1 to m do
   if d[a[j,2]]>d[a[j,1]]+w[a[j,1],a[j,2]] then
    d[a[j,2]]:=d[a[j,1]]+w[a[j,1],a[j,2]];

  for j:=1 to m do
   if d[a[j,2]]>d[a[j,1]]+w[a[j,1],a[j,2]] then
    begin
    writeln('successful conspiracy');
    exit;
    end;
  writeln('lamentable kingdom');
end;

 

begin
 while true do
  begin
  read(n);
  if n=0 then exit;
  {for i:=1 to 100 do w[0,i]:=0;}
  for i:=0{1} to 100 do
   for j:=0 to 100 do
    w[i,j]:=maxlongint div 2;
  fillchar(a,sizeof(a),0);
  read(m);
  for i:=1 to m do
   begin
   read(x,y);
   read(c);
   read(cc);
   read(c);
   read(c);
   read(z);
   if cc='l' then begin w[x+y,x-1]:=z-1; a[i,1]:=x+y; a[i,2]:=x-1; end;
   if cc='g' then begin w[x-1,x+y]:=-z-1;a[i,1]:=x-1; a[i,2]:=x+y; end;
   end;
  work;
  end;
end.

 

 

SPFA算法,这个就但疼了,做了好久。

f数组 要开大一些

还有一个很神奇的地方,d数组赋初始值时不一定为0,可以为任何数。

因为我没有设置超级原点,那么为了让其他点能进入队列,只能在开始时把它们全部放进去

d[i]数组表示超级原点到i的距离,而初始值并不影响后面的距离变化。

var
 c,cc:char;
 n,m,x,i,j,y,z,max:longint;
 w:array[0..110,0..110]of longint;
 d:array[0..110]of longint;
 f:array[0..5000]of longint;

procedure work;
var
 i,j,pan,head,tail:longint;
 mark:array[0..110]of boolean;
 t:array[0..110]of longint;
begin
 fillchar(d,sizeof(d),0);
 fillchar(mark,sizeof(mark),0);
 fillchar(f,sizeof(f),0);
 fillchar(t,sizeof(t),0);

 head:=1;
 tail:=0;

 for i:=0 to n do
  begin
  inc(tail);
  f[tail]:=i;
  end;

 while head<=tail do
  begin
  for i:=0 to n do
   if w[f[head],i]<>maxlongint div 2 then
    if d[i]>d[f[head]]+w[f[head],i] then
     begin
     d[i]:=d[f[head]]+w[f[head],i];
     if not mark[i] then
      begin
      mark[i]:=true;
      inc(t[i]);
      if t[i]>n then
       begin
       writeln('successful conspiracy');
       exit;
       end;
      inc(tail);
      f[tail]:=i;
      end;
     end;
    mark[f[head]]:=false;
    inc(head);
  end;

  writeln('lamentable kingdom');
end;

begin
 while true do
  begin
  read(n);
  if n=0 then exit;

  for i:=0 to 110 do
   for j:=0 to 110 do
    w[i,j]:=maxlongint div 2;


  read(m);
  for i:=1 to m do
   begin
   read(x,y);
   read(c);
   read(cc);
   read(c); read(c);
   read(z);
   if cc='l' then w[x+y,x-1]:=z-1;
   if cc='g' then w[x-1,x+y]:=-z-1;
   end;
  work;
  end;
end.


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值