【备战NOIP2012图论专项模拟试题】外星人入侵

Description

外星人入侵地球。可怕的吃人外星人正在全国各地依次序建立它们的基地。

全国共有N(1≤ N ≤10,000)座城市,城市编号1~N。城市之间有M(0≤ M ≤100,000)条双向道路相连。外星人计划建立A(0≤A≤N)个基地。

你只有在距离当前所有外星人基地至少K(1≤K≤100)单位长度的城市才能得到安全。

所以你必须赶快写一个程序决定走到哪里去。

Input

第1行:4个整数N, M, A, K

接下来M行,每行3个整数T1, T2(1≤T1 < <script type="math/tex" id="MathJax-Element-3"><</script>T2≤N)和D(1≤D≤100),表示城市T1与T2之间有一条长度为D的道路。两个城市之间最多有一条直连道路。

接下来A行,每行1个整数Bi(1≤Bi≤N),表示外星人依次序建的第i个基地所在的城市编号。

Output

共A行,第i行1个整数,表示当外星人建好第i个基地后,距离当前所有基地B1,B2,…,Bi至少K长度的城市的数量。

Sample Input

7 6 3 3

1 2 1

1 3 1

2 5 1

3 6 1

1 4 1

4 7 2

2

1

4

Sample Output

2

1

0

分析:
我们一开始以第一个基地为起点先跑一遍SPFA。然后对于每个基地,我们都进行BFS。然后会超时。我们开k比较小,就可以优化一下。我们用d[i]表示从基地跑到i点后,还能跑多远。然后当我们从x到y时,w为这两点的距离,如果d[x]+w<=d[y]或者
d[x]+w<=0时,我们就无需再找了。

代码:

const
  MaxE=10001;
  MaxV=210001;
  maxn=50001;
type
 rec=record
  x,y,w,next:longint;
 end;
var
  n,m,c,q,i,x,y,t,s,p,ans,w:longint;
  g:array [1..Maxv] of rec;
  ls:array [1..Maxe] of longint;
  b:array [1..maxe] of boolean;
  v,d,list:array [1..maxe] of longint;

procedure spfa;
var
  head,tail,t,i:longint;
begin
  head:=0; tail:=1;
  list[1]:=c;
  for i:=1 to n do
  d[i]:=maxlongint;
  d[c]:=0;
  v[c]:=1;
  while head<>tail do
    begin
      head:=head mod maxe+1;
      t:=ls[list[head]];
      while t>0 do
        with g[t] do
          begin
            if d[x]+w<d[y] then
              begin
                d[y]:=d[x]+w;
                if v[y]=0 then
                  begin
                    v[y]:=1;
                    tail:=tail mod maxe+1;
                    list[tail]:=y;
                  end;
              end;
            t:=next;
          end;
      v[list[head]]:=0;
    end;
 ans:=0;
 for i:=1 to n do
  begin
   if q-d[i]<=0 then begin b[i]:=true; inc(ans); end
                else b[i]:=false;
   d[i]:=q-d[i];
  end;
 writeln(ans);
end;

procedure bfs(xx:longint);
var l:array [0..maxn+1] of longint;
    head,tail,t:longint;
begin
 head:=0; tail:=1;
 l[1]:=xx;
 d[xx]:=q;
 if b[xx] then begin ans:=ans-1; b[xx]:=false; end;
 repeat
   head:=head mod maxn+1;
   t:=ls[l[head]];
   while t>0 do
    begin
     with g[t] do
      begin
       if (d[x]-w>d[y]) and (d[x]-w>0) then
        begin
         d[y]:=d[x]-w;
         if b[y] then begin ans:=ans-1; b[y]:=false; end;
         tail:=tail mod maxn+1;
         l[tail]:=y;
        end;
       t:=next;
      end;
    end;
 until head=tail;
 writeln(ans);
end;

begin
   readln(n,m,p,q);
  for i:=1 to m do
   begin
    readln(x,y,w);
    g[i*2-1].x:=x;
    g[i*2-1].y:=y;
    g[i*2-1].w:=w;
    g[i*2-1].next:=ls[x];
    ls[x]:=i*2-1;
    g[i*2].y:=x;
    g[i*2].x:=y;
    g[i*2].w:=w;
    g[i*2].next:=ls[y];
    ls[y]:=i*2;
   end;
 if p>0 then
 begin
  readln(c);
  spfa;
  for i:=2 to p do
   begin
    readln(c);
    bfs(c);
   end;
 end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值