动态规划:计算连续跳跃列表的所有可能结束位置
Posted
技术标签:
【中文标题】动态规划:计算连续跳跃列表的所有可能结束位置【英文标题】:Dynamic Programming: Calculate all possible end positions for a list of consecutive jumps 【发布时间】:2014-11-17 10:42:40 【问题描述】:问题在于计算所有可能的结束位置以及每个位置存在多少组合。
给定起始位置x=0
、轨道长度m
和跳跃列表。返回区间 [-m/2,+m/2] 上每个位置的可能结束数。跳跃必须按照给定的顺序进行,但可以以消极或积极的方式完成。
例如:
L = 40
jumps = 10, 10
解决方案:
-20 : 1 (-10, -10)
0 : 2 (-10,+10 & +10,-10)
20 : 1 (+10,+10)
(需要的输出只有一对“位置:#combinations”)
我做了一个简单的递归,结果还可以。 但在大量数据中,执行时间是几分钟或几小时。 我知道使用动态编程可以在几秒钟内得到解决方案,但我不知道在这种情况下如何应用动态。
这是我实际的递归函数:
void escriuPosibilitats(queue<int> q, map<int,int> &res, int posicio, int m)
int salt = q.front();
q.pop();
if(esSaltValid(m,posicio,-salt))
int novaPosicio = posicio - salt;
if(q.empty())
res[novaPosicio]++;
else
escriuPosibilitats(q,res,novaPosicio,m);
if(esSaltValid(m,posicio,salt))
int novaPosicio = posicio + salt;
if(q.empty())
res[novaPosicio]++;
else
escriuPosibilitats(q,res,novaPosicio,m);
-
其中
q
是剩余跳转的队列。
res
是主要解决方案。
posicio
是实际位置。
m
是轨道的长度。
其中esSaltValid
是一个检查跳转是否在轨道长度范围内有效的函数。
PD:对不起我的英语水平。我试图改善我的问题!谢谢=)
【问题讨论】:
【参考方案1】:您可以使用以下想法。令 dp[x][i] 为在跳转 i 之前到达位置 x 的路径数。那么答案将是每个 x 的 dp[x][N],其中 N 是跳跃次数。更重要的是,你可以意识到这个 dp 只依赖于前一行,然后你可以简单地 dp[x] 并将下一行保存在某个辅助数组中,然后在每次迭代中替换它。代码是这样的:
const int MOD = (int)(1e8+7);
const int L = 100;
int N = 36;
int dx[] = 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1;
int dp[L+1];
int next[L+1];
int main()
int shift = L/2; // to handle negative indexes
dp[shift] = 1; // the initial position has one way to arrive, since you start there
for (int i = 0; i < N; ++i) // for each jump size
for (int x = -L/2; x <= L/2; ++x) // for each possible position
if (-L/2 <= x + dx[i] && x + dx[i] <= L/2) // positive jump
next[x + shift] = (next[x + shift] + dp[x + dx[i] + shift]) % MOD;
if (-L/2 <= x - dx[i] && x - dx[i] <= L/2) // negative jump
next[x + shift] = (next[x + shift] + dp[x - dx[i] + shift]) % MOD;
for (int x = -L/2; x <= L/2; ++x) // update current dp to next and clear next
dp[x+shift] = next[x+shift];
next[x+shift] = 0;
for (int x = -L/2; x <= L/2; ++x) // print the result
if (dp[x+shift] != 0)
cout << x << ": " << dp[x+shift] << '\n';
当然,如果 L 太大而无法处理,您可以压缩状态空间并将结果保存在映射中,而不是保存在数组中。该方法的复杂度为 O(L*N)。希望对您有所帮助。
编辑:只需计算所有模 1e8+7 即可。
【讨论】:
在某些情况下是不正确的。例如:L = 100 N = 36 dx = 1s 例如在:L = 100 N = 36 dx = 1s 它返回负数和错误数字 假设“1s”在这种情况下表示 dx 是一个由 36 个 1 组成的数组,那么负数是因为结果太大而无法容纳 32 位整数。将类型更改为 long long。 @user1782922 究竟哪个值是错误的?他们在我看来还不错。 例如:-16返回254186856,正确答案是54186842以上是关于动态规划:计算连续跳跃列表的所有可能结束位置的主要内容,如果未能解决你的问题,请参考以下文章
js-leetcode前端动态规划入门第四天刷题打卡「跳跃游戏」贪心大法!
LeetCodeLeetCode之跳跃游戏Ⅱ——暴力解法+动态规划+贪婪算法