查找从4x4阵列的左上角到右下角的所有可能路径

时间:2014-12-14 20:59:52

标签: ruby

我有一些挑战需要解决..

  

机器人位于4x4网格的左上角。机器人可以向上,向下,向左或向右移动,但不能两次访问同一地点。机器人正试图到达网格的右下角。

     

打印机器人到达目的地的唯一方式。

我试图通过检查网格中的所有可能路径并计算所有导致退出位置的路径来解决它。像建造一个有所有可能运动的树一样的东西。

                              (0,0)

            (0,1)                               (1,0)

    (1,1)           (0,2)               (1,1)           (2,0)

(0,1)(1,2)(2,1)   (2,1)(3,0)             ***             ***

      ***            ***

我写了一些代码......

class Robot

  def self.count_possible_ways

    board = Array.new(4,0) { Array.new(4,0) }

    @@count = 0

    find_possible_ways(board)
    print_output(board)
    puts "Ile razy: #{@@count}"
  end

  def self.find_possible_ways(board)

    entry_position_yx = [0,0]
    exit_position_yx = [3,3]

    actual_position = entry_position_yx

    board[actual_position[0]][actual_position[1]] = 1
    find_possible_ways_2(board,actual_position)
  end

  def self.find_possible_ways_2(board,actual_position)
    puts "Actual position: (#{actual_position[0]},#{actual_position[1]})"
    check_possible_moves(board,actual_position)
  end



  def self.check_possible_moves(board,actual_position)

    if actual_position[1] != 0
      if board[actual_position[0]][actual_position[1]-1] == 0
        board[actual_position[0]][actual_position[1]-1] = 1
        actual_position = [actual_position[0],actual_position[1]-1]
        if actual_position == [3,3]
          @@count +=1
        else
          find_possible_ways_2(board,actual_position)
        end
      end
    end
    if actual_position[1] != 3
      if board[actual_position[0]][actual_position[1]+1] == 0
        board[actual_position[0]][actual_position[1]+1] = 1
        actual_position = [actual_position[0],actual_position[1]+1]
        if actual_position == [3,3]
          @@count +=1
          else
          find_possible_ways_2(board,actual_position)
        end
      end
    end
    if actual_position[0] != 0
      if board[actual_position[0]-1][actual_position[1]] == 0
        board[actual_position[0]-1][actual_position[1]] = 1
        actual_position = [actual_position[0]-1,actual_position[1]]
        if actual_position == [3,3]
          @@count +=1
          else
          find_possible_ways_2(board,actual_position)
        end
      end
    end
    if actual_position[0] != 3
      if board[actual_position[0]+1][actual_position[1]] == 0

        board[actual_position[0]+1][actual_position[1]] = 1
        actual_position = [actual_position[0]+1,actual_position[1]]
        if actual_position == [3,3]
          @@count +=1
          else
          find_possible_ways_2(board,actual_position)
        end
      end
    end
  end



  def self.print_output(board)
    board.each do |row|
      puts row.join(" ")
    end
  end
end


Robot.count_possible_ways

..但我的问题是....在每一步(就像路径的每个新分支)我想创建一个新的独立数组。我无法检查同一阵列上的每个可能的路径。我认为必须使用递归,但我不知道如何编码。

我不确定我是否解释得很好,但每次我的路径分成两条新路径时,我都需要创建一个新对象(数组)。

2 个答案:

答案 0 :(得分:3)

是的,递归是可行的方法。

<强>代码

def paths(grid, partial_path = [[0,0]], paths = [])
  return paths if grid.empty?
  last_cell = partial_path.last
  grid.each do |cell|
    if adjacent?(last_cell,cell)
      pp = partial_path + [cell]
      if cell == [3,3]
        paths << pp
      else
        paths(grid-[cell], pp, paths)
      end
    end  
  end
  paths
end

def adjacent?(a,b)
  ra, ca = a
  rb, cb = b
  ((ra==rb) && (ca==cb+1 || ca==cb-1)) ||
  ((ca==cb) && (ra==rb+1 || ra==rb-1))
end

<强>计算

grid = Array.new(16) { |i| i.divmod(4) } - [[0, 0]]
  #=> [[0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0],
  #    [2, 1], [2, 2], [2, 3], [3, 0], [3, 1], [3, 2], [3, 3]]

paths(grid).size
  #=> 184

paths(grid).values_at(34, 72, 138)
  #=> [[[0, 0], [0, 1], [0, 2], [1, 2], [1, 1], [1, 0], [2, 0],
  #     [3, 0], [3, 1], [3, 2], [2, 2], [2, 3], [3, 3]],
  #
  #    [[0, 0], [0, 1], [1, 1], [1, 2], [1, 3], [2, 3], [2, 2],
  #     [2, 1], [2, 0], [3, 0], [3, 1], [3, 2], [3, 3]],
  #
  #    [[0, 0], [1, 0], [2, 0], [2, 1], [1, 1], [0, 1], [0, 2],
  #     [1, 2], [2, 2], [2, 3], [3, 3]]]

如果允许机器人也沿着对角线移动,请将adjacent更改为:

def adjacent?(a,b)
  ((a.first-b.first).abs <= 1) && ((a.last-b.last).abs <= 1)
end

进行更改后,paths(grid).size #=> 96371

@Halfbit写了一些代码来显示机器人的游荡。 (见他对该链接的评论)。这是184条路径中的79条。

enter image description here


               (105 paths not shown)

enter image description here

答案 1 :(得分:0)

修改

在它上面睡一晚;意识到,我已经监督了你问题中的“所有问题”,所以我的答案是错误的,因为你得到的只是最短的。 我不删除“答案”,因为它可能对其他人有用


虽然这听起来像'家庭作业',或者听起来像是这样,但我用一种完全不同的算法回答:

你只需要一个阵列......

由于机器人不允许“返回”,即两次使用一个点,你可以使用逻辑,用于印刷电路板设计:只需编号可能(空)邻居方块... ( - 代表空的)

第1次

1 - - -
- - - -
- - - -
- - - - 

第二

1 2 - -
2 - - - 
- - - - 
- - - -

最后

1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7

现在从7(最高)回到较低的...... 7-6-5-4-3-2-1 ......

不是一个聪明的算法吗? (由你自己编码; - )

即便如此(S:开始,E:结束和X被阻止)......(可能是你的下一个作业)

S - - - X -
- - X - - -
- - X - - -
X X X X - X
E - - - - -

- &GT;

S 2 3 4 X 8
2 3 X 5 6 7
3 4 X 6 7 8
X X X X 8 X
E C B A 9 A