Vanya and Treasure CodeForces - 677D (综合暴力、bfs更新均摊时间复杂度)

题目链接

题目大意

n*m的矩阵里,有1, 2, ..., p 这些箱子,每种箱子都起码有一个,箱子p只有一个。1号箱子是开着的,其他都是锁着的。i号箱子里有i+1号箱子的钥匙。从矩阵左上角,也就是(1, 1)开始走路,求最短多少步可以打开p号箱子。可以上下左右走不能斜着走,一次只能走一格。

n, m的规模是300。

思路

首先要找到两种基本思路。

第一种,暴力找每个i-1箱子到每个i箱子的最少步数,一直找到p,这样最坏时间复杂度是O(n*m*n*m),就比如所有数字就是一半数量的1和一半数量的2,就达到了最坏情况。

第二种,bfs找每个i-1箱子到每个i箱子的最少步数,一直找到p。这样最坏时间复杂度也是O(n*m*n*m)。因为每更新一次,就要bfs整张图一次,是n*m的复杂度。最坏的情况,每个数都是不一样的,就要bfs整张图n*m次,达到最坏复杂度。

但是这两种方法却是互补的。第一种方法,在箱子i-1和箱子i的数量之积比较小的时候是一种高效的解法,而第二种在箱子i-1和箱子i的数量之积比较大,也就是箱子种类p比较小(数量之积大也就是每种箱子数量都比较大,那样势必使得总共箱子的种类p会更小)的时候是一种高效的解法。那选择方法的依据是什么呢?

答案是,依据箱子的数量之积。假设现在在更新i号箱子,若i号箱子有nowsize个,i-1号箱子有lastsize个,它们乘积小于n*m时,用暴力匹配更新;大于n*m时,用bfs更新。这样的时间复杂度是O(nmsqrt(nm)),n*m的大于/小于的条件,使得两种方法各自均摊了复杂度。过程的话,bfs那种可以根据条件用基本不等式,算出每次更新需要的计算次数、总共更新次数的关系,两者相乘是nmsqrt(nm)的数量级。暴力匹配我还没有想得特别清楚,只是想到了可以从lastsize*nowsize由小变大,而复杂度也在由小变大演变的角度考虑,复杂度最大演变到nmsqrt(nm),就是lastsize*nowsize=n*m的边界情况。

反思

知道思路以后,一夜加一上午地敲和改,太多小错误了。

1.bfs一定要在新增加节点入队的时候就把这个点标记掉。刚开始生生等到下一次这个节点出队的时候才标记,就会导致很多节点被重复入队4次,这就是开始MLE的原因。以此纪念我的首发MLE

2.长代码取变量名一定要斟酌清楚,目前的理解来讲,应该宁可取长一点也不要取容易相互用错的变量名。debug的时候被用错下标里面变量名的自己蠢哭了。

猜你喜欢

转载自blog.csdn.net/xuzonghao/article/details/88757077