POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap
来源:互联网 发布:qq解冻软件最新版 编辑:程序博客网 时间:2024/04/29 12:29
POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap
本来就有点小感冒,不过看到就快出国了,还是陪下爸妈,去海边玩了下,结果连续的长途开车奔波,加上海边游泳,消耗了不少体力,终于今天回来彻底病倒,喉咙痛到说不出话。打算这两天就把之前玩的一些题目给总结了吧,接下来得开始弄各种手续和那边导师安排的工作了。
POJ3635,很有一道意思的题目,最后做出来后,你会发现它既有SPFA和Dijkstra的朴素思想,又有动态规划的巧妙,但是又不能生搬硬套这些算法。
我一开始想到的是用动规,推导出:
costArr[i][j] = min{ ( e(i,i') + (j - k) ) * price[i'] + costArr[i‘][k] }
其中costArr[i][j]为起点s到达某点i时,还剩下单位油量j的最小代价;e(i,i')表示相邻的两个点i,i'的边长;price[i]表示点i的单位汽油价格。该公式意思是枚举和点i相邻的各个状态:costArr[i'][k],从而找出最优的选择。
得到该公式后,算法的流程就和Dijkstra几乎一样了,稍微不一样是这里把costArr[i'][k]当做一个状态。然后算法的每次迭代就从最小堆中拿出最小的costArr[i'][k],更新和它相邻的状态点costArr[i][j]。这样子一共有n*c个状态点。
然后我根据该公式写成的代码,测试了好些数据,都ok,结果一提交,居然time exceeds limitation。无奈之下去再参考下别人的思路,发现该题时间要求比较严格,原来还要剪枝。如何剪枝?核心是“每个状态点,只加1单位油,或者不加油直接走到相邻状态点”,这样子也可以把所有的n*c个状态点给遍历。
至于算法复杂度,窃以为,用最小堆实现,参考Dijkstra的算法复杂度分析,上面的原始算法和剪枝优化的复杂度都是为O( (nc+ec)*log(nc) ),只是剪枝优化后有点深度搜索的味道,尽可能的往纵深去搜索,实际应用中,往往只需要遍历更小的状态数就可以到达终点。这个分析,如有不对万望各位兄台指正。
- import java.util.*;
- class Node
- {
- public Node()
- {
- nodeId = -1;
- price = 0;
- links = new ArrayList<Link>();
- }
- public Node(int id, int p)
- {
- nodeId = id;
- price = p;
- links = new ArrayList<Link>();
- }
- public int nodeId;
- public int price;
- public ArrayList<Link> links;
- }
- class Link
- {
- public Link()
- {
- lnodeId = -1;
- distance = 0;
- }
- public Link(int nId, int dis)
- {
- lnodeId = nId;
- distance = dis;
- }
- public int lnodeId;
- public int distance;
- }
- class StateNode
- {
- public StateNode()
- {
- }
- public StateNode(int nId, int cap, int cost)
- {
- this.nodeId = nId;
- this.cap = cap;
- this.cost = cost;
- }
- public int nodeId;
- public int cap;
- public int cost;
- }
- class Comp implements Comparator<StateNode>
- {
- @Override
- public int compare(StateNode arg0, StateNode arg1) {
- return arg0.cost - arg1.cost;
- }
- }
- public class Main {
- public static int costArr[][] = new int[1001][101];
- public static boolean visFlag[][] = new boolean[1001][101];
- public static int MAX = 1<<30;
- //关键的算法函数。
- public static int DijSearch(ArrayList<Node>graph, int s, int e, int c)
- {
- int minCost = -1;
- int n = graph.size();
- for(int i=0;i<n;i++)
- {
- Arrays.fill(costArr[i], MAX);
- Arrays.fill(visFlag[i], false);
- }
- //Initialize the start node.
- costArr[s][0] = 0;
- PriorityQueue<StateNode> queue = new PriorityQueue<StateNode>(n*(c+1),new Comp());
- queue.add(new StateNode(s,0,0));
- while(queue.isEmpty() == false)
- {
- StateNode hn = queue.poll();
- if(hn.nodeId == e && hn.cap == 0)
- {
- minCost = hn.cost;
- break;
- }
- if(visFlag[hn.nodeId][hn.cap] == true)
- {
- continue;
- }
- else
- {
- visFlag[hn.nodeId][hn.cap] = true;
- }
- //Plus one.
- if(hn.cap + 1 <= c && costArr[hn.nodeId][hn.cap+1] > costArr[hn.nodeId][hn.cap] + graph.get(hn.nodeId).price)
- {
- costArr[hn.nodeId][hn.cap+1] = costArr[hn.nodeId][hn.cap] + graph.get(hn.nodeId).price;
- queue.add(new StateNode(hn.nodeId,hn.cap+1,costArr[hn.nodeId][hn.cap+1]));
- }
- ArrayList<Link> links = graph.get(hn.nodeId).links;
- for(int i=0;i<links.size();i++)
- {
- int lnId = links.get(i).lnodeId;
- int linkDis = links.get(i).distance;
- if(linkDis > c || linkDis > hn.cap)
- continue;
- // Go over costArr[ links[i].nodeId ][j]
- if ((visFlag[lnId][hn.cap - linkDis] == false)) {
- if ( (hn.cost < costArr[lnId][hn.cap - linkDis]) ) {
- costArr[lnId][hn.cap - linkDis] = hn.cost;
- queue.add(new StateNode(lnId, hn.cap - linkDis, hn.cost));
- }
- }
- }
- }
- return minCost;
- }
- public static void main(String[] args)
- {
- Scanner scan = new Scanner(System.in);
- int n,m;
- n = scan.nextInt();
- m = scan.nextInt();
- //Initialize the graph
- ArrayList<Node> graph = new ArrayList<Node>(n);
- //The nodes
- for(int i=0;i<n;i++)
- {
- int pri = scan.nextInt();
- graph.add(new Node(i,pri));
- }
- //The edges
- for(int i=0;i<m;i++)
- {
- int u,v,d;
- u = scan.nextInt();
- v = scan.nextInt();
- d = scan.nextInt();
- graph.get(u).links.add(new Link(v,d));
- graph.get(v).links.add(new Link(u,d));
- }
- //The query
- int q,s,e,c;
- q = scan.nextInt();
- for(int i=0;i<q;i++)
- {
- c = scan.nextInt();
- s = scan.nextInt();
- e = scan.nextInt();
- int dis = DijSearch(graph, s, e, c);
- if(dis == -1)
- System.out.println("impossible");
- else
- System.out.println(dis);
- }
- }
- }
- POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap
- POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap
- POJ 2263 Heavy Cargo (SPFA+Dijkstra,最短路变形)
- POJ2253 Frogger(最短路变形,floyd,Dijkstra,spfa)
- Gym-100851F Froggy Ford 最短路变形 dijkstra || spfa
- ZOJ-2008-一个最短路问题-(dijkstra+heap,spfa)
- 最短路-Dijkstra+heap
- HDU2544:最短路【Dijkstra & SPFA】
- 最短路 spfa, dijkstra, Floyd
- 最短路spfa dijkstra模板
- HDU2544:最短路(Dijkstra,SPFA)
- 最短路【dijkstra】【floyd 】【spfa】
- 最短路(dijkstra、spfa)
- HDOJ 1596 find the safest road ((最短路变形) Dijkstra && SPFA)
- HDOJ 2680 Choose the best route (最短路变形 Dijkstra && SPFA)
- POJ 3013 Big Christmas Tree【最短路变形,DIjkstra堆优化+spfa算法】
- poj1062 昂贵的婚礼 最短路变形 spfa 枚举 思考
- POJ 2253 Frogger 最短路-Dijkstra的变形形式
- 程序员面试宝典(第二版)要点汇总
- POJ2449 第k最短路径
- spring和redis的整合
- 4、Spring MVC+Hibernate4.2.1
- hdu 4160 Dolls
- POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap
- 7. 小心共享
- Java程序员应该知道的10个调试技巧
- AssetBundle loading failed because.....已解决
- struts标签的if判断的几个实用方法 两个对象属性比较
- linux pcapy安装问题
- poj 2411 Mondriaan's Dream(状态压缩dp)
- Steps for creating android applications using NDK and ARM assembly language
- 对于0-1分数规划的Dinkelbach算法的分析