NOIP2009最优贸易——史上最详细解析
2015-08-07 11:59
302 查看
[解题思路]
本题很直观的就是想找到一个价格最低和一个价格最高点(满足由起点能到达,且又可顺序到达终点),找最低价格的点可以这样来处理,从源点开始找到所有点的最低价格(某个顶点的最低价格就是从源点到该所有可能路径上的价格最低的点),最后枚举卖出的点,并且判断该点是否可以到达即可。此外,由于数据规模较大,一般的邻接矩阵难以承受,因此采用动态数据结构邻接表。但是本题有环,处理时还有几个细节问题:
1.由于是最后要判定所有的顶点是否可以到达终点,因此不妨将所有的边反向,由终点出发判断终点可以到达那些顶点就可以了,并做上标记。这样也就要求在读入边的时候必须反向再储存一次。
2.用SPFA求某个顶点的最低价格时,对SPFA进行了改进。由SPFA的原理可以知道,该算法可以处理环的问题,但是要求最短路径的长度是可以收敛的,也就是说不能在图中存在负权。该题目满足此要求。SPFA是用来求最短路径的算法,在此对其改进,来求路径上最小价格的点
[参考程序]
program trade; var belong,pri,time,maxp,minp,de:array[0..200001]of longint; pre,head,v,ipre,ihead,iv:array[0..500001]of longint; q:array[0..100000]of longint; vis:array[0..100000]of boolean; itot,tot,i,j,k,n,m,t,now,ans:longint; procedure add(x,y:longint); //这是用邻接表(数组方式)来存储这个图 begin //关于邻接表,可以点击代码下方的连接既有详细解释 inc(tot); //tot表示第几条路 给每条边一个编号 v[tot]:=y; //v[i]是编号为i的边的目的地 pre[tot]:=head[x]; //pre[i]表示编号为i的点的前一条边的编号 head[x]:=tot; //head[x]是起点为x的边的最后一个编号(因为每次有新的都更新) end; procedure iadd(x,y:longint); //和上面一样不用解释了吧 begin inc(itot); iv[itot]:=y; ipre[itot]:=ihead[x]; ihead[x]:=itot; end; function max(a,b:longint):longint; //求大值 begin if a>b then exit(a) else exit(b); end; function min(a,b:longint):longint; //求小值 begin if a<b then exit(a) else exit(b);end; procedure init; var i,x,y,z:longint; begin readln(n,m); //n个城市m条路 for i:=1 to n do read(pri[i]); //pri[i]即price价格 for i:=1 to m do begin readln(x,y,z); //起点终点有向无向 add(x,y); //第一个邻接表存图 iadd(y,x); //第二个邻接表存反向图 if z=2 then begin add(y,x);iadd(x,y);end; //2说明是两个方向要反着再来一次 end; end; procedure spfa1; //正着一遍找小值 var l,r,i,j,k:longint; begin for i:=2 to n do minp[i]:=maxlongint; //minp[i]是能到第i个点的最小值 初始化要放大值(为什么他不放每个点的原本的价格QAQ) minp[1]:=pri[1]; //从1点开始搜1当然能到自己 q[1]:=1;vis[1]:=true; //q[i]是队列 存顶点 vis[i]是访问标记 l:=0;r:=1; //l队头 r队尾 while l<>r do begin inc(l); i:=head[q[l]]; //i是关于队头顶点的一条边的编号(刚刚的tot) vis[q[l]]:=false; //标记顶点 while i<>0 do //i=0时就说明这个顶点开始的所有边已经遍历完 begin if minp[v[i]]>minp[q[l]] then //v[i]是这条边的终点 begin minp[v[i]]:=minp[q[l]]; if not vis[v[i]] then //如果这个点不在队里就入队 begin vis[v[i]]:=true; inc(r); q[r]:=v[i]; end; end; i:=pre[i];//继续上一条边 end; end; for i:= 1 to n do if minp[i]<>maxlongint then minp[i]:=min(pri[i],minp[i]); //因为他不放原本价格所以这次要再比一次 end; procedure spfa2; //反着一边找小值 var l,r,i,j,k:longint; begin for i:=1 to n do vis[i]:=false; q[1]:=n;vis :=true; maxp :=pri ; l:=0;r:=1; while l<>r do begin inc(l); maxp[q[l]]:=max(maxp[q[l]],pri[q[l]]); i:=ihead[q[l]]; vis[q[l]]:=false; while i<>0 do begin if maxp[iv[i]]<maxp[q[l]] then begin maxp[iv[i]]:=maxp[q[l]]; if not vis[iv[i]] then begin vis[iv[i]]:=true; inc(r); q[r]:=iv[i]; end; end; i:=ipre[i]; end; end; end; begin init; spfa1; spfa2; for i:=1 to n do if maxp[i]-minp[i]>ans then ans:=maxp[i]-minp[i]; //依次枚举每个城市求最大差价 writeln(ans); end.
数据结构之邻接表
相关文章推荐
- Nginx版本的“helloworld”
- DWR反向Ajax的一个简单Web聊天
- jQuery实现仿腾讯视频列表分页效果的方法
- Android中通过typeface设置字体
- 解决eclipse无法查看v4,v7-appcompat源码
- Treap
- IntelliJ Idea 常用插件
- has leaked window com.android.internal.policy.impl.PhoneWindow$ that was originally added here异常解决
- JVM之——虚拟机类加载机制
- 关于c语言的typedef高级用法 typedef void (*post_sync_t)(CO_Data*);
- PHP中使用curl伪造IP的简单方法
- MyBatis 的简单应用
- poj2051解题报告(优先队列)
- ant安装配置问题:ANT_HOME is set incorrectly or ant could not be located. Please set ANT_HOME.
- .NET调用window串口读取电子秤的数据
- http://www.sqlservercentral.com/articles/Failover+Clustered+Instance+(FCI)/92196/
- IOS中的三大事件
- KMP算法
- jquery 过滤器区分
- Mahout推荐系统引擎UserCF中的IRStats部分源码解析