NOIP2009 提高组 最优贸易 解题报告

题目描述

输入


输出

  共1行,包含1个整数,表示最多以赚取的旅费。如果没有进行贸易,则输出0、

样例输入

5 54 3 5 6 11 2 11 4 12 3 23 5 14 5 2

样例输出

5



(1)、解题思路:

本题很直观的就是想找到一个价格最低和一个价格最高点(满足由起点能到达,且又可顺序到达终点),找最低价格的点可以这样来处理,从源点开始找到所有点的最低价格(某个顶点的最低价格就是从源点到该所有可能路径上的价格最低的点),最后枚举卖出的点,并且判断该点是否可以到达即可。此外,由于数据规模较大,一般的邻接矩阵难以承受,因此采用动态数据结构邻接表。但是本题有环,处理时还有几个细节问题:

1.由于是最后要判定所有的顶点是否可以到达终点,因此不妨将所有的边反向,由终点出发判断终点可以到达那些顶点就可以了,并做上标记。这样也就要求在读入边的时候必须反向再储存一次。

2.用SPFA求某个顶点的最低价格时,对SPFA进行了改进。由SPFA的原理可以知道,该算法可以处理环的问题,但是要求最短路径的长度是可以收敛的,也就是说不能在图中存在负权。该题目满足此要求。SPFA是用来求最短路径的算法,在此对其改进,来求路径上最小价格的点

(2)、代码详解:

program zuiyoumaoyi;

type point=record

   other,pre:longint

  end;

var p:array[0..500000]of point;

    last:array[1..100000]oflongint;

   max,min,cost:array[1..100000]of longint;//最大差价,最低价,价格

    q:array[1..1000000]oflongint;//队列

    v:array[1..100000]ofboolean;//判断是否入队

    n,r:longint;

 

procedure build(a,b:longint);//建立两城市之间的关系

begin

  inc(r);

  p[r].other:=b;

  p[r].pre:=last[a];

  last[a]:=r;

end;

 

procedure init;

var i,m,x,y,z:longint;

begin

  readln(n,m);//读入城市数和道路数

  for i:=1 to n do

    begin

      read(cost[i]);//读入各城市价值

     min[i]:=cost[i];//赋值为最小价值

    end;

  for i:=1 to m do

    begin

      readln(x,y,z);//读入各城市关系

      build(x,y);//建立关系

      if z=2 thenbuild(y,x);//两城市间双向通行

    end;

end;

 

procedure spfa;

var head,tail,i,j,x:longint;

begin

  fillchar(v,sizeof(v),false);

  q[1]:=1;head:=1;tail:=1;v[1]:=true;//队列的初始状态,1为起点

  while head<=tail do//队列不空

    begin

      x:=q[head];//取队首元素

      j:=last[x];

      whilej<>0 do

       begin

         i:=p[j].other;

         if (min[i]>min[x])or(max[i]<=max[x]) then

           begin

             if min[i]>min[x] then min[i]:=min[x];//修改                              最短路

             if max[i]<max[x] then max[i]:=max[x];

                   if cost[i]-min[i]>max[i]then max[i]:=cost[i]-min[i];

             if not v[i] then//拓展节点入队

              begin

                inc(tail);

                q[tail]:=i;

                v[i]:=true;

              end;

           end;

         j:=p[j].pre;

       end;

      v[x]:=false;//释放结点,一定要释放,因为此节点有可能下次用来松弛其他节点

      inc(head);//出队

      ifhead>100000 then exit;

    end;

end;

 

begin

  init;

  spfa;

  writeln(max[n]);

end. 

 

(3)、心得体会:

1.SPFA的功能与理解,不能仅仅局限于求最短路,而可以是图中某点到图中所有点的某种关系。比如说本题中可以用来求某点到1的所有路径中的Wmax。

2.实践出真知,只有亲自动手动脑练习,才能真正了解并掌握各类算法及代码的意义和用法。

3.学会善于利用网络资源。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值