【问题标题】: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);
        }
    }
}
  1. 其中q 是剩余跳转的队列。
  2. res 是主要解决方案。
  3. posicio 是实际位置。
  4. m 是轨道的长度。
  5. 其中esSaltValid 是一个检查跳转是否在轨道长度范围内有效的函数。

PD:对不起我的英语水平。我试图改善我的问题!谢谢=)

【问题讨论】:

    标签: c++ algorithm dynamic-programming


    【解决方案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
    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多