Problem p01411 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 503

double dp[2][101][101];
bool is_exist[NUM];
int line_loc[NUM], can_write_num[NUM];

int main() {

  int H, N, P, M, K;
  scanf("%d %d %d %d %d", &H, &N, &P, &M, &K);

  for (int i = 0; i <= H + 1; i++) {
    is_exist[i] = false;
    can_write_num[i] = 1; // その高さ以下で、横棒を引ける高さの数
  }

  int height, loc;
  for (int loop = 0; loop < M; loop++) {
    scanf("%d %d", &height, &loc);
    is_exist[height] = true;
    line_loc[height] = loc;
    can_write_num[height] = 0;
  }

  for (int h = 2; h <= H + 1; h++)
    can_write_num[h] += can_write_num[h - 1];

  for (int i = 0; i < 2; i++) {
    for (int k = 0; k <= K; k++) {
      for (int pos = 1; pos <= N; pos++)
        dp[i][k][pos] = 0; // dp[高さ][横棒の設置本数][位置] = ゴール確率
    }
  }

  int CURRENT = 0, NEXT = 1;

  dp[CURRENT][0][P] = 1.0;

  double loc_possi = 1.0 / (double)(N - 1), height_possi;

  for (int h = H; h >= 1; h--) {
    if (is_exist
            [h]) { // 既に横棒が引かれている場合:該当する2箇所の確率を交換する

      for (int num = 0; num <= K; num++) {
        swap(dp[CURRENT][num][line_loc[h]], dp[CURRENT][num][line_loc[h] + 1]);
      }

    } else { // 横棒が引かれていない場合

      for (int num = 0; num <= K; num++) {
        for (int pos = 1; pos <= N; pos++)
          dp[NEXT][num][pos] = 0.0;
      }

      for (int num = 0; num <= K; num++) {

        height_possi = (double)(K - num) /
                       (double)can_write_num[h]; // その高さが選ばれる確率

        for (int pos = 1; pos <= N; pos++) {

          // 右に動く(★交換回数が1増える!!★)
          if (pos != N) {
            dp[NEXT][num + 1][pos + 1] +=
                height_possi * loc_possi * dp[CURRENT][num][pos];
          }

          // 左に動く(★交換回数が1増える!!★)
          if (pos != 1) {
            dp[NEXT][num + 1][pos - 1] +=
                height_possi * loc_possi * dp[CURRENT][num][pos];
          }

          // ★変わらず★
          // 自分の高さが選ばれない場合
          dp[NEXT][num][pos] += (1 - height_possi) * dp[CURRENT][num][pos];

          // 自分の高さが選ばれ、かつ自分以外の場所が選ばれる場合
          if (pos != 1 && pos != N) {
            dp[NEXT][num + 1][pos] +=
                height_possi * (1.0 - loc_possi * 2) * dp[CURRENT][num][pos];
          } else { // pos == 1 || pos == N
            dp[NEXT][num + 1][pos] +=
                height_possi * (1.0 - loc_possi) * dp[CURRENT][num][pos];
          }
        }
      }
      swap(CURRENT, NEXT);
    }
  }

  double ans = 0.0;
  for (int pos = 1; pos <= N; pos++)
    ans = max(ans, dp[CURRENT][K][pos]);

  printf("%.10lf\n", ans);

  return 0;
}


Fixed submission:
#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 503

double dp[2][102][102];
bool is_exist[NUM];
int line_loc[NUM], can_write_num[NUM];

int main() {

  int H, N, P, M, K;
  scanf("%d %d %d %d %d", &H, &N, &P, &M, &K);

  for (int i = 0; i <= H + 1; i++) {
    is_exist[i] = false;
    can_write_num[i] = 1; // その高さ以下で、横棒を引ける高さの数
  }

  int height, loc;
  for (int loop = 0; loop < M; loop++) {
    scanf("%d %d", &height, &loc);
    is_exist[height] = true;
    line_loc[height] = loc;
    can_write_num[height] = 0;
  }

  for (int h = 2; h <= H + 1; h++)
    can_write_num[h] += can_write_num[h - 1];

  for (int i = 0; i < 2; i++) {
    for (int k = 0; k <= K; k++) {
      for (int pos = 1; pos <= N; pos++)
        dp[i][k][pos] = 0; // dp[高さ][横棒の設置本数][位置] = ゴール確率
    }
  }

  int CURRENT = 0, NEXT = 1;

  dp[CURRENT][0][P] = 1.0;

  double loc_possi = 1.0 / (double)(N - 1), height_possi;

  for (int h = H; h >= 1; h--) {
    if (is_exist
            [h]) { // 既に横棒が引かれている場合:該当する2箇所の確率を交換する

      for (int num = 0; num <= K; num++) {
        swap(dp[CURRENT][num][line_loc[h]], dp[CURRENT][num][line_loc[h] + 1]);
      }

    } else { // 横棒が引かれていない場合

      for (int num = 0; num <= K; num++) {
        for (int pos = 1; pos <= N; pos++)
          dp[NEXT][num][pos] = 0.0;
      }

      for (int num = 0; num <= K; num++) {

        height_possi = (double)(K - num) /
                       (double)can_write_num[h]; // その高さが選ばれる確率

        for (int pos = 1; pos <= N; pos++) {

          // 右に動く(★交換回数が1増える!!★)
          if (pos != N) {
            dp[NEXT][num + 1][pos + 1] +=
                height_possi * loc_possi * dp[CURRENT][num][pos];
          }

          // 左に動く(★交換回数が1増える!!★)
          if (pos != 1) {
            dp[NEXT][num + 1][pos - 1] +=
                height_possi * loc_possi * dp[CURRENT][num][pos];
          }

          // ★変わらず★
          // 自分の高さが選ばれない場合
          dp[NEXT][num][pos] += (1 - height_possi) * dp[CURRENT][num][pos];

          // 自分の高さが選ばれ、かつ自分以外の場所が選ばれる場合
          if (pos != 1 && pos != N) {
            dp[NEXT][num + 1][pos] +=
                height_possi * (1.0 - loc_possi * 2) * dp[CURRENT][num][pos];
          } else { // pos == 1 || pos == N
            dp[NEXT][num + 1][pos] +=
                height_possi * (1.0 - loc_possi) * dp[CURRENT][num][pos];
          }
        }
      }
      swap(CURRENT, NEXT);
    }
  }

  double ans = 0.0;
  for (int pos = 1; pos <= N; pos++)
    ans = max(ans, dp[CURRENT][K][pos]);

  printf("%.10lf\n", ans);

  return 0;
}