Noip2009模拟题_收费站(cost)

收费站(cost.pas/c/cpp)


【题目描述】


        在某个遥远的国家里,有n个城市。编号为1,2,3,……,n。
        这个国家的政府修建了m条双向的公路。每条公路连接着两个城市。沿着某条公路,开车从一个城市到另一个城


市,需要花费一定的汽油。
        开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。所有的收费站都在城市中,在城市间


的公路上没有任何的收费站。
        小红现在要开车从城市u到城市v(1<=u,v<=n)。她的车最多可以装下s升的汽油。在出发的时候,车的油箱是满


的,并且她在路上不想加油。
        在路上,每经过一个城市,她要交一定的费用。如果她某次交的费用比较多,她的心情就会变得很糟。所以她


想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。这个问题对于她来说太难了,于是她找到


了聪明的你,你能帮帮她吗?


【输入格式】


        第一行5个正整数,n,m,u,v,s。分别表示有n个城市,m条公路,从城市u到城市v,车的油箱的容量为s升。
        接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
        再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从


城市ai到城市bi,或者从城市bi到城市ai,需要用ci升汽油。


【输出格式】


        仅一个整数,表示小红交费最多的一次的最小值。
        如果她无法到达城市v,输出-1。


【输入样例1】


        4 4 2 3 8
        8
        5
        6
        10
        2 1 2
        2 4 1
        1 3 4
        3 4 3


【输出样例1】


        8


【输入样例2】


        4 4 2 3 3
        8
        5
        6
        10
        2 1 2
        2 4 1
        1 3 4
        3 4 3


【输出样例2】


        -1


【数据规模】


        对于60%的数据,满足n<=200,m<=10000,s<=200
        对于100%的数据,满足n<=10000,m<=50000,s<=1000000000
        对于100%的数据,满足ci<=1000000000,fi<=1000000000,可能有两条边连接着相同的城市。


算法:二分答案+最短路


这道题算是挺简单的二分答案+最短路验证了。考试的时候没有时间做了,下来之后又做了一遍,发现还不错啊……
二分的时候我们二分那个最小费用(一开始把费用理解错了,理解成全部的费用了。。),然后做一遍SPFA,当经过某个点的费用大于这个最小费用就略过这条边,起点也是一样。

最后看终点的最短路,如果油超过了容量则不成立,不成立的话就往右找,否则向左找。

program cost;

const
 maxn=10000;
 maxm=10000000;

type
 atp=record
  y,next,dis:longint;
 end;

var
 n,m,st,ed,rest,min,max,tot,head,tail:longint;
 a,first,v:array [0..maxn] of longint;
 b:array [0..maxn] of boolean;
 map:array [0..maxm] of atp;
 que:array [0..maxm] of longint;

procedure init;
var
 i,x,y,dis:longint;
begin
 min:=maxlongint;
 readln(n,m,st,ed,rest);
 for i:=1 to n do
  begin
   readln(a[i]);
   if a[i]<min then min:=a[i];
   if a[i]>max then max:=a[i];
  end;
 for i:=1 to m do
  begin
   readln(x,y,dis);
   inc(tot);
   map[tot].y:=y;
   map[tot].next:=first[x];
   map[tot].dis:=dis;
   first[x]:=tot;
   inc(tot);
   map[tot].y:=x;
   map[tot].next:=first[y];
   map[tot].dis:=dis;
   first[y]:=tot;
  end;
end;

function SPFA(x:longint):boolean;
var
 t:longint;
begin
 if a[st]>x then exit(true);
 fillchar(b,sizeof(b),false);
 fillchar(v,sizeof(v),100);
 v[st]:=0;
 que[1]:=st;
 b[st]:=true;
 head:=0;
 tail:=1;
 while head<tail do
  begin
   inc(head);
   t:=first[que[head]];
   while t>0 do
    begin
     if a[map[t].y]>x then
      begin
       t:=map[t].next;
       continue;
      end;
     if v[que[head]]+map[t].dis<v[map[t].y] then
      begin
       v[map[t].y]:=v[que[head]]+map[t].dis;
       if not b[map[t].y] then
        begin
         b[map[t].y]:=true;
         inc(tail);
         que[tail]:=map[t].y;
        end;
      end;
     t:=map[t].next;
    end;
   b[que[head]]:=false;
  end;
 if v[ed]>rest then exit(true) else exit(false);
end;

procedure main;
var
 l,r,mid:longint;
begin
 l:=min;
 r:=max;
 if SPFA(max) then
  begin
   writeln(-1);
   close(input);
   close(output);
   halt;
  end;
 while l<r do
  begin
   mid:=(l+r) shr 1;
   if not SPFA(mid) then r:=mid else l:=mid+1;
  end;
 writeln(l);
end;

begin
 assign(input,'cost.in'); reset(input);
 assign(output,'cost.out'); rewrite(output);

 init;
 main;

 close(input); close(output);
end.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值