POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap

来源:互联网 发布:qq解冻软件最新版 编辑:程序博客网 时间:2024/04/29 12:29

POJ3635 周游诸城:变形的SPFA/Dijkstra最短路+动规思想+Heap

分类: Algorithm 126人阅读 评论(0) 收藏 举报

  本来就有点小感冒,不过看到就快出国了,还是陪下爸妈,去海边玩了下,结果连续的长途开车奔波,加上海边游泳,消耗了不少体力,终于今天回来彻底病倒,喉咙痛到说不出话。打算这两天就把之前玩的一些题目给总结了吧,接下来得开始弄各种手续和那边导师安排的工作了。

  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) ),只是剪枝优化后有点深度搜索的味道,尽可能的往纵深去搜索,实际应用中,往往只需要遍历更小的状态数就可以到达终点。这个分析,如有不对万望各位兄台指正。

 

[java] view plaincopy
  1. import java.util.*;  
  2.   
  3.   
  4. class Node  
  5. {  
  6.     public Node()  
  7.     {  
  8.         nodeId = -1;  
  9.         price = 0;  
  10.         links = new ArrayList<Link>();  
  11.     }  
  12.       
  13.     public Node(int id, int p)  
  14.     {  
  15.         nodeId = id;  
  16.         price = p;  
  17.         links = new ArrayList<Link>();  
  18.     }  
  19.       
  20.     public int nodeId;  
  21.     public int price;  
  22.     public ArrayList<Link> links;  
  23. }  
  24.   
  25. class Link  
  26. {  
  27.     public Link()  
  28.     {  
  29.         lnodeId = -1;  
  30.         distance = 0;  
  31.     }  
  32.     public Link(int nId, int dis)  
  33.     {  
  34.         lnodeId = nId;  
  35.         distance = dis;  
  36.     }  
  37.       
  38.     public int lnodeId;  
  39.     public int distance;  
  40. }  
  41.   
  42.   
  43. class StateNode  
  44. {  
  45.     public StateNode()  
  46.     {  
  47.           
  48.     }  
  49.       
  50.     public StateNode(int nId, int cap, int cost)  
  51.     {  
  52.         this.nodeId = nId;  
  53.         this.cap = cap;  
  54.         this.cost = cost;  
  55.     }  
  56.     public int nodeId;  
  57.     public int cap;  
  58.     public int cost;  
  59. }  
  60.   
  61. class Comp implements Comparator<StateNode>  
  62. {  
  63.     @Override  
  64.     public int compare(StateNode arg0, StateNode arg1) {  
  65.         return arg0.cost - arg1.cost;  
  66.     }  
  67.       
  68. }  
  69.   
  70. public class Main {  
  71.       
  72.     public static int costArr[][] = new int[1001][101];  
  73.     public static boolean visFlag[][] = new boolean[1001][101];  
  74.     public static int MAX = 1<<30;  
  75.       
  76.       
  77.     //关键的算法函数。  
  78.     public static int DijSearch(ArrayList<Node>graph, int s, int e, int c)  
  79.     {  
  80.         int minCost = -1;  
  81.         int n = graph.size();  
  82.           
  83.         for(int i=0;i<n;i++)  
  84.         {  
  85.             Arrays.fill(costArr[i], MAX);  
  86.             Arrays.fill(visFlag[i], false);  
  87.         }  
  88.           
  89.         //Initialize the start node.  
  90.         costArr[s][0] = 0;  
  91.           
  92.         PriorityQueue<StateNode> queue = new PriorityQueue<StateNode>(n*(c+1),new Comp());  
  93.           
  94.         queue.add(new StateNode(s,0,0));  
  95.           
  96.         while(queue.isEmpty() == false)  
  97.         {  
  98.             StateNode hn = queue.poll();  
  99.               
  100.             if(hn.nodeId == e && hn.cap == 0)  
  101.             {  
  102.                 minCost = hn.cost;  
  103.                 break;  
  104.             }  
  105.               
  106.             if(visFlag[hn.nodeId][hn.cap]  == true)  
  107.             {  
  108.                 continue;  
  109.             }  
  110.             else  
  111.             {  
  112.                 visFlag[hn.nodeId][hn.cap] = true;  
  113.             }  
  114.               
  115.             //Plus one.  
  116.             if(hn.cap + 1 <= c && costArr[hn.nodeId][hn.cap+1] > costArr[hn.nodeId][hn.cap] + graph.get(hn.nodeId).price)  
  117.             {  
  118.                 costArr[hn.nodeId][hn.cap+1] = costArr[hn.nodeId][hn.cap] + graph.get(hn.nodeId).price;  
  119.                 queue.add(new StateNode(hn.nodeId,hn.cap+1,costArr[hn.nodeId][hn.cap+1]));  
  120.             }  
  121.   
  122.               
  123.               
  124.             ArrayList<Link> links = graph.get(hn.nodeId).links;  
  125.               
  126.             for(int i=0;i<links.size();i++)  
  127.             {  
  128.                 int lnId = links.get(i).lnodeId;  
  129.                 int linkDis = links.get(i).distance;   
  130.                 if(linkDis > c || linkDis > hn.cap)  
  131.                     continue;  
  132.                   
  133.   
  134.                 // Go over costArr[ links[i].nodeId ][j]  
  135.                 if ((visFlag[lnId][hn.cap - linkDis] == false)) {  
  136.                     if ( (hn.cost < costArr[lnId][hn.cap - linkDis]) ) {  
  137.                         costArr[lnId][hn.cap - linkDis] =  hn.cost;  
  138.                         queue.add(new StateNode(lnId, hn.cap - linkDis, hn.cost));  
  139.                     }  
  140.                 }  
  141.                   
  142.                   
  143.             }  
  144.         }  
  145.           
  146.         return minCost;  
  147.     }  
  148.       
  149.   
  150.       
  151.     public static void main(String[] args)  
  152.     {  
  153.         Scanner scan = new Scanner(System.in);  
  154.         int n,m;  
  155.         n = scan.nextInt();  
  156.         m = scan.nextInt();  
  157.           
  158.         //Initialize the graph  
  159.         ArrayList<Node> graph = new ArrayList<Node>(n);  
  160.           
  161.         //The nodes  
  162.         for(int i=0;i<n;i++)  
  163.         {  
  164.             int pri = scan.nextInt();  
  165.             graph.add(new Node(i,pri));  
  166.         }  
  167.           
  168.         //The edges  
  169.         for(int i=0;i<m;i++)  
  170.         {  
  171.             int u,v,d;  
  172.             u = scan.nextInt();  
  173.             v = scan.nextInt();  
  174.             d = scan.nextInt();  
  175.               
  176.               
  177.             graph.get(u).links.add(new Link(v,d));  
  178.             graph.get(v).links.add(new Link(u,d));  
  179.         }  
  180.           
  181.           
  182.           
  183.           
  184.           
  185.         //The query  
  186.         int q,s,e,c;  
  187.         q = scan.nextInt();  
  188.         for(int i=0;i<q;i++)  
  189.         {  
  190.             c = scan.nextInt();  
  191.             s = scan.nextInt();  
  192.             e = scan.nextInt();  
  193.               
  194.             int dis = DijSearch(graph, s, e, c);   
  195.               
  196.             if(dis == -1)  
  197.                 System.out.println("impossible");  
  198.             else  
  199.                 System.out.println(dis);  
  200.         }  
  201.       
  202.     }  
  203.   
  204. }