zoukankan      html  css  js  c++  java
  • [NOIP2013]华容道 题解

    [NOIP2013]华容道

    首先是一种比较显然的做法。

    整个棋盘,除了起点,终点和空格,其他的方块是等价的。

    对于终点,它始终不会变化,如果搜到终点结束搜索即可,所以我们不需要考虑终点。

    所以需要考虑的是空格的位置和起点方块的位置。

    定义$f(i1,j1,i2,j2)$为

    空格所在坐标$(i1,j1)$  起点坐标$(i2,j2)$。

    对于每一步,可以移动空格周围的一个可移动棋子,将它与空格位置交换。其实等价于空格移动到和空格相邻的棋子。如果该棋子是起点,则将起点更新到原来空格的坐标。

    使用bfs,每次步数加一,队列内的状态步数满足单调,第一次得到(区别于dijkstra,不是第一次取出)的任何一个状态就是最优。当第一次得到起点坐标等于终点坐标时,直接返回答案。

    如果到最后也没有得到起点坐标等于终点坐标,返回-1表示无解。

    这一种做法实际上遍历了可能得到答案的所有情况,应该不是正解。

    复杂度O(n²m²q),期望得分80,不太好剪枝。

     

     

     这道题的正解使我想到了另一道题。进阶指南0x25节中推箱子一题。也使用了bfs。

    空格到处乱跑,其实是没有意义的,如果它不在起点的周围四个格子,它永远无法使起点靠近终点。

    所以我们固定空格在起点的周围四个点,并用当前的状态去更新以后的状态。

    每次取出,一种更新方式是直接与起点交换,二是将该位置交换到起点的另一个方向。

    因为每次的增量不保证相同,这一次不保证第一次得到是最优了,所以要使用spfa或者dijkstra来跑最短路。

    如果像推箱子一样双重bfs,那么你一定还是会tle,甚至比以前跑得更慢。因为复杂度一点都没有降下来。

    问题在这一道题是多测,解决办法是预处理,只要O(n²m²)对每一个点更新一下到其他点的距离即可。

  • 相关阅读:
    hdu5728 PowMod
    CF1156E Special Segments of Permutation
    CF1182E Product Oriented Recurrence
    CF1082E Increasing Frequency
    CF623B Array GCD
    CF1168B Good Triple
    CF1175E Minimal Segment Cover
    php 正则
    windows 下安装composer
    windows apache "The requested operation has failed" 启动失败
  • 原文地址:https://www.cnblogs.com/skyh/p/11200785.html
Copyright © 2011-2022 走看看