矩阵状态“恢复”

问题描述 投票:0回答:1

我正在尝试处理二维列表中的数据。我知道所有对象都是不可变的。我的递归调用正在回溯,状态正在消失。当你没有状态时,处理这个问题的标准方法是什么?

defmodule Euler do
  def euler_15() do
    grid = create_2d_list(10, 10)
    # write out 1's to the first row
    grid = write_out_first_row(grid, 0)
    grid = write_out_first_column(grid, 0)
    fill_out_remainder(grid, 1, 1)
  end

  def fill_out_remainder(grid, 10, _) do
    IO.puts("finale to fill_out_remainder")
  end

  def write_out_column(grid, row, 10) do
    IO.puts("finale! to write out column is running for row: #{row}")
  end

  def write_out_column(grid, row, col) do
    IO.puts("*** write out column is running for column: #{col} and row: #{row}")
    IO.puts("Reading from this grid state")
    IO.inspect(grid)
    cell_above = get_element(grid, row-1, col) 
    IO.puts("value from column above is: #{cell_above}")
    cell_left = get_element(grid, row, col-1)
    IO.puts("value from left cell is: #{cell_left}")
    grid = set_element(grid,row,col,cell_above+cell_left)
    IO.inspect(grid)
    write_out_column(grid, row, col+1)
  end

  def write_out_row(grid, row) do
    write_out_column(grid, row, 1)
  end

  def fill_out_remainder(grid, row_ct, col_ct) do
    write_out_row(grid, row_ct)
    fill_out_remainder(grid, row_ct + 1, col_ct)
  end

  def write_out_first_row(grid, 10) do
    grid
  end

  def write_out_first_row(grid, counter) do
    grid = set_element(grid, 0, counter, 1)
    write_out_first_row(grid, counter + 1)
  end

  def write_out_first_column(grid, 10) do
    grid
  end

  def write_out_first_column(grid, counter) do
    grid = set_element(grid, counter, 0, 1)
    write_out_first_column(grid, counter + 1)
  end

  def create_2d_list(rows, cols) do
    for _ <- 1..rows, do: for(_ <- 1..cols, do: nil)
  end

  def get_element(grid, r, c) do
    # first step - extract the row
    the_row = Enum.at(grid, r)
    # now get the value
    Enum.at(the_row,c)
  end

  def set_element(grid, r, c, new_value) do
    # stage 1 - extract the row
    the_row = Enum.at(grid, r)
    # stage 2 - update the row
    the_row = List.replace_at(the_row, c, new_value)
    # stage 3 - update the 2d lists row to be changed
    # with the updated row
    grid = List.replace_at(grid, r, the_row)
    grid
  end
end

Euler.euler_15()
elixir
1个回答
0
投票

Euler 15 是一个典型的动态规划问题。这是我的方法。 (所有指数均从 1 开始)

自上而下的 DP(又名记忆化)

“标准”方法是进行递归调用 将状态与所有其他参数一起获取, 并返回该递归的结果 以及更新后的状态。

defmodule Euler do
  def euler_15(rows, cols) do
    # The first arg is the "state",
    # which I prefer to call it "memo".
    {routes, _memo} = solve(%{}, rows, cols, 1, 1)
    routes
  end

  # The recursive function should return
  # both the number of routes
  # and the updated memo.
  defp solve(memo, rows, _cols, rows, _j), do: {1, memo}
  defp solve(memo, _rows, cols, _i, cols), do: {1, memo}

  defp solve(memo, rows, cols, i, j) do
    case memo[{i, j}] do
      nil ->
        {right, memo} = solve(memo, rows, cols, i, j + 1)
        {down, memo} = solve(memo, rows, cols, i + 1, j)
        routes = right + down
        memo = Map.put(memo, {i, j}, routes)
        {routes, memo}

      routes ->
        {routes, memo}
    end
  end
end

自上而下DP V2

这是我通过恢复可变性来解决记忆问题的方法。这比 V1 更容易编码并且运行速度更快。

defmodule Euler do
  def euler_15(rows, cols) do
    # Because we are going to use process dictionary as the memo,
    # and we don't want to pollute the process dictionary of the caller,
    # we just spawn a child process to do all the nasty work.
    Task.async(fn ->
      solve(rows, cols, 1, 1)
    end)
    |> Task.await()
  end

  # The process dictionary is the memo,
  # so we don't need to pass in the memo any more.
  # We don't need to return the memo, either.
  defp solve(rows, _cols, rows, _j), do: 1
  defp solve(_rows, cols, _i, cols), do: 1

  defp solve(rows, cols, i, j) do
    memoized({i, j}, fn ->
      right = solve(rows, cols, i, j + 1)
      down = solve(rows, cols, i + 1, j)
      right + down
    end)
  end

  defp memoized(key, fun) do
    case Process.get(key) do
      nil ->
        val = fun.()
        Process.put(key, val)
        val

      val ->
        val
    end
  end
end

自下而上DP

您仍然需要跟踪更新的备忘录。

defmodule Euler do
  def euler_15(rows, cols) do
    memo = for i <- 1..rows, into: %{} do
      {{i, 1}, 1}
    end

    memo = for j <- 1..cols, into: memo do
      {{1, j}, 1}
    end

    memo = for i <- 2..rows, j <- 2..cols, reduce: memo do
      memo -> Map.put(memo, {i, j}, memo[{i - 1, j}] + memo[{i, j - 1}])
    end

    memo[{rows, cols}]
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.