机器人走路问题
就是一个坐标轴,从1开始到N,机器人处于其中某个位置cur,问它走到另一个位置aim有几种走法?限定机器人必须走k步。且在1或N位置的时候,只能返回2或N-1,其余位置两个方向都能走。
首先理解一下递归。
机器人从cur位置开始走,假如这个cur在1这个位置,那么它只能去2;假如cur在N这个位置,它只能去N-1;假如cur在中间,那么cur可以去cur-1或者cur+1的位置。
此时机器人只走了1步,剩下k-1步。
那么下一步机器人处在一个新位置,这个位置我们从上一步结果可以知道,因此递归。
递归出口就是k=0,表示机器人走完。走完就代表一个机器人的一个走法。
判断这个走法是不是我们要的结果,就是判断cur和aim有没有重合?重合代表走对了,返回1,否则,这个走法不是我们要的,返回0;
int way1(int cur, int aim, int k, int N) { if (k == 0) return cur == aim ? 1 : 0; if (cur == 1) return way1(2, aim, k - 1, N); if (cur == N) return way1(N - 1, aim, k - 1, N); return way1(cur - 1, aim, k - 1, N) + way1(cur + 1, aim, k - 1, N); }
接下来我们要优化这个递归过程。为什么?因为递归的过程有大量的重复计算。
比方说机器人已经开始走了,它走到了5这个位置,那么5可以从4过来,也可以从6过来。
想一下,假设我们规定机器人从1开始走100步,坐标轴长度N=10。
机器人出现在5和6这个位置很多次,其中一定有存在,机器人走了同样的步数,走到了5或者6。
这在我们的递归里,就是重复计算的过程。
所以加上一个缓存表,存的是,机器人在当前位置和剩余步数的情况下,递归是否计算过这个数据。
假如计算过,直接返回计算的值;没计算过,更新缓存表。
//二维缓存表cs,维度<N+1,k+1>,初始化-1,表示没计算过。
int way2(int cur, int aim, int k, int N,vector<vector<int>>& cs) { if (cs[cur][k] != -1) return cs[cur][k]; int ans = 0; if (k == 0) ans = (cur == aim ? 1 : 0); else if (cur == 1) ans = way2(2, aim, k - 1, N, cs); else if (cur == N) ans = way2(N - 1, aim, k - 1, N, cs); else ans = way2(cur - 1, aim, k - 1, N, cs) + way2(cur + 1, aim, k - 1, N, cs); cs[cur][k] = ans; return ans; }
继续优化就有点蒙了,是根据表找依赖关系,直接得到答案。
(这也是动态规划难的地方,就像数学公式,不给你推导,只告诉你结论,谁知道怎么来的?
所以最后还是从浅入深才能领悟精髓啊。)
完全理解之后再补充。
posted on 2023-06-22 03:44 WhatAnyWay 阅读(49) 评论(0) 收藏 举报
浙公网安备 33010602011771号