8.16 恶魔城 1128

题目

上帝需要创造一位战士去消灭撒旦,这位战士必须要穿过恶魔城才能与撒旦决斗。恶魔城内有M条连接N个路口(从1到N编号)的街道,每一条街道都是单向的(也就是说你不能逆着该街道指定的方向走),并且在城内无论怎么走都不可能走回原来走过的地方。开始的时候,战士的生命力(HP)为INITHP、站在1号路口,而撒旦在第N号路口等待着他。每一条街道上都有许多魔鬼,但是也有一些街道已经被上帝派去的天使占领了。当战士经过连接i号向j号路口的街道时,如果占领该街道的是恶魔,那么他的HP先加倍然后减少L[i,j],我们记为A[i,j]=-L[i,j];如果占领该街道的是天使,那么他的HP就会先加倍然后增加L[i,j],我们记为A[i,j]=+L[i,j];如果该街道不存在,那么A[i,j]=0。如果某一时刻战士的HP<=0,那么他会死亡。因为这个战士将非常无敌,当他见到撒旦的时候只要还活着,就能一口气把撒旦消灭,所以上帝不希望让他的INITHP过高。
  给定N,A[1..N,1..N],求最小的INITHP,使这个战士能够活着见到撒旦。
第一行有一个正整数N(3 ≤ N ≤ 100),下面跟着的第i行第j个数为A[i,j](绝对值不超过10000的整数)。

4                                4
0 -4 0 –10
0 0 +3 0
0 0 0 –14
0 0 0 0

题解

传说中用Dfs就可以过,然而我已经打了那么长的二分+SPFA,懒得改了,于是就将就着用了。

确定最小的HP值(1)和最大的HP值(10000够了),二分答案,用SPFA判断答案,输出r
注意HP值可能累加得太大,应限制以避免运算上溢

看到吗,下面这个东西就是害我改了一晚上的罪魁祸首——清零!要不是我翻出以前的标对比,我永远也不会想到,我改了一个晚上就是因为清零!从此再也不会不清零。
b[v[h]]:=0;

O(n2logn)n2

代码

var
  n,i,j,k,t,mid,l,r:longint;
  x,y,ne,ls,w,d,b:array[0..10005]of longint;
  v:array[0..100005]of longint;

function spfa(c:longint):boolean;
var
  i,k,h,t:longint;
begin
  fillchar(d,sizeof(d),0);
  fillchar(b,sizeof(b),0);
  h:=0;t:=1;v[1]:=1;d[1]:=c;b[1]:=1;
  while h<t do
    begin
      inc(h);
      k:=ls[v[h]];
      while k>0 do
        begin
          if d[x[k]]*2+w[k]>d[y[k]] then
            begin
              if d[x[k]]*2+w[k]<10000000 then
              d[y[k]]:=d[x[k]]*2+w[k] else d[y[k]]:=10000000;
              if b[y[k]]=0 then
                begin
                  b[y[k]]:=1;
                  inc(t);
                  v[t]:=y[k];
                end;
            end;
          k:=ne[k];
        end;
      b[v[h]]:=0;
    end;
  if d[n]>0 then exit(true) else exit(false);
end;

begin
  assign(input,'satanic.in7');
  assign(output,'satanic.out');
  reset(input);rewrite(output);
  readln(n);
  l:=1;
  for i:=1 to n do
    begin
      for j:=1 to n do
        begin
          read(k);
          if k<>0 then
            begin
              inc(t);
              x[t]:=i;y[t]:=j;w[t]:=k;
              ne[t]:=ls[x[t]];
              ls[x[t]]:=t;
            end;
        end;
    end;
  r:=10000;
  while l<r do
    begin
      mid:=(l+r) div 2;
      if spfa(mid) then r:=mid else l:=mid+1;
    end;
  writeln(r);
  close(input);close(output);
end.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值