Как получить диагональные значения из конкретной точки? - PullRequest
0 голосов
/ 24 октября 2018

Предположим, у меня матрица 10x10 со следующими данными:

 1     2     3     4     5     6     7     8     9    10 
11    12    13    14    15    16    17    18    19    20 
21    22    23    24    25    26    27    28    29    30 
31    32    33    34    35    36    37    38    39    40 
41    42    43    44     _    46    47    48    49    50 
51    52    53    54    55    56    57    58    59    60 
61    62    63    64    65    66    67    68    69    70 
71    72    73    74    75    76    77    78    79    80 
81    82    83    84    85    86    87    88    89    90 
91    92    93    94    95    96    97    98    99   100

Моя позиция в [4][4].Как я могу перечислить диагональные значения из этой позиции?

Например, ожидаемый результат будет:

[56, 67, 78, 89, 100, 1, 12, 23, 34]
[54, 63, 72, 81, 9, 18, 27, 36]

Мое текущее решение

  def next?(index, row, size)
    (((row + index) % size) + 1 ) % size
  end

  (1...chess_size).each do |l|
    next_el, curr_el = next?(l, row, chess_size), (row + l) % chess_size

    # this gets me the first diagnonal. Note that it prints out wrong value
    tmp[0] << chess[curr_el][curr_el]

    # this gets me the values from current row below to up
    tmp[1] << chess[(row + l) % chess_size][row]
    tmp[2] << chess[-l][l]
    tmp[3] << chess[row][(row + l) % chess_size]
  end

Наша матрица будетвсегда иметь одинаковое количество строк и столбцов.

Ответы [ 6 ]

0 голосов
/ 31 октября 2018

Это решение проблемы Хакерранка Атака Королевы .

Код

def count_moves(n, obs, qrow, qcol)
  qdiff = qrow-qcol
  qsum =  qrow+qcol  
  l = u = -1
  r = d =  n
  ul = qdiff >= 0 ? qrow-qcol-1 : -1
  dr = qdiff >= 0 ? n           : qrow+n-qcol
  ur = qsum < n   ? -1          : qrow-n+qcol
  dl = qsum < n   ? qrow+qcol+1 : n
  obs.uniq.each do |i,j|
    case i <=> qrow
    when -1               # up
      case j <=> qcol
      when -1               # up-left
        ul = [ul,i].max
      when 0                # up same col
        u  = [u,i].max
      when 1                # up-right
        ur = [ur,i].max
      end
    when 0                # same row
      j < qcol ? (l = [l,j].max) : r = [r,j].min
    else                  # down
      case j <=> qcol
      when -1               # down-left
        dl = [dl,i].min
      when 0                # down same col
        d  = [d,i].min
      when 1                # down-right
        dr = [dr,i].min
      end
    end
  end
  r + dl + d + dr - l - ul -u - ur - 8
end

Пример

Предположим, что на шахматной доске есть 9 строк и столбцов, где местоположение ферзя показано символом q, а каждое препятствие - буквой o.Все остальные местоположения обозначены буквой x.Мы видим, что у королевы есть 16 возможных ходов (7 вверх и вниз, 6 влево и вправо, 1 по диагонали вверх-слева-вниз-вправо и 2 вверх-вправо-вниз-лева диагональ.

arr = [
  %w| x x x x x x x x x |, # 0
  %w| o x x x x x x x x |, # 1
  %w| x o x x x x x x x |, # 2
  %w| x x o x x x x x o |, # 3
  %w| x x x o x x x x x |, # 4
  %w| x x x x x x o x x |, # 5
  %w| o o x x x q x x x |, # 6
  %w| x x x x x x o x x |, # 7
  %w| x x x x x o x x x |  # 8
#     0 1 2 3 4 5 6 7 8   
]

qrow = qcol = nil
obs = []
n = arr.size
arr.each_with_index do |a,i|
  a.each_with_index do |c,j|
    case c
    when 'o'
      obs << [i,j]
    when 'q'
      qrow=i
      qcol=j
    end
  end
end

qrow
  #=> 6
qcol
  #=> 5
obs
  #=> [[1, 0], [2, 1], [3, 2], [3, 8], [4, 3], [5, 6], [6, 0], [6, 1], [7, 6], [8, 5]]

count_moves(n, obs, qrow, qcol)
  #=> 16

Объяснение

  • l - это самый большой индекс столбца препятствия встрока королевы, которая меньше индекса столбца королевы;
  • r - индекс наименьшего столбца препятствия в королевах, который больше индекса столбца королевы;
  • uсамый большой индекс строки препятствия в столбце королевы, который меньше индекса строки королевы;
  • d - самый маленький индекс строки препятствия в столбце королевы, который больше, чем строка королевыindex;
  • ul - наибольший индекс строки препятствия на диагонали сверху-слева-внизу-королевы, который меньше индекса строки королевы;
  • dr - это значениенаименьший индекс строки препятствия на ходуверхняя левая-нижняя правая диагональ n, которая больше, чем индекс строки ферзя;
  • ur - это наибольший индекс строки препятствия на диагонали сверху-вниз-слева ферзя, который меньше чеминдекс строки королевы;и
  • dl - наименьший индекс строки препятствия на диагонали сверху-справа-внизу ферзя, который больше индекса строки ферзя.

Для примеравыше, прежде чем препятствия будут приняты во внимание, эти переменные устанавливаются в следующие значения:

l  =  0
r  =  9
ul =  0 
u  = -1
ur =  2
dl =  9
d  =  9
dr =  9

Обратите внимание, что если у ферзя есть индексы строк и столбцов qrow и qcol,

  • i - j = qrow - qcol для всех мест [i, j] по диагонали сверху-слева-внизу-королевы;и
  • i + j = grow + gcol для всех мест [i, j] на диагонали сверху-справа-внизу ферзя

Затем мы проходим все (уникальные) препятствия, определяя для каждогонаходится ли она в строке, в столбце или в одной из диагоналей королевы, а затем заменяет значение применимой переменной ее индексом строки или столбца, если оно «ближе» к королеве, чем ранее расположенное ближе всего место.

Если, например, препятствие находится в строке королевы, а индекс ее столбца j меньше индекса столбца королевы, выполняется следующий расчет:

l = [l, j].max

Аналогично, еслипрепятствие расположено по диагонали сверху-слева-снизу-ферзя, а индекс строки i меньше индекса строки ферзя; вычисление будет:

ul = [ul, i].max

После всех препятствий из приведенного выше примерасчиталось, что переменные имеют следующие значения:

l  #=>  1
r  #=>  9
ul #=>  4
u  #=> -1
ur #=>  5
dl #=>  9
d  #=>  8
dr #=>  7

Наконец, мы вычисляем общее количество квадратов, на которые может переместиться королева.е.

qcol - l  - 1 +  # left
r - qcol  - 1 +  # right
u - qrow  - 1 +  # up
grow - d  - 1 +  # down
ul - qrow - 1 +  # up-left
ur - qrow - 1 +  # up-right
qrow - dl - 1 +  # down-left
qrow - dr - 1    # down-right

, что упрощается до

r + dl + d + dr - l - ul -u - ur - 8
  #=> 9 + 9 + 8 + 7 - 1 - 4 + 1 - 5 - 8 => 16
0 голосов
/ 30 октября 2018

@ CarySwoveland Кажется, @Jamy работает над еще одной проблемой от hackerrank queens-attack.

Проблема довольно сложная, потому что идея состоит в том, чтобы вообще никогда не создавать матрицу.То есть контрольные примеры становятся очень большими, и, следовательно, сложность пространства будет проблемой.

Я изменил свою реализацию, но все же потерпел неудачу из-за проблемы тайм-аута (это потому, что контрольные примеры стали очень большими).Я не уверен, как сделать его работоспособным.

Прежде чем я покажу код.Позвольте мне объяснить, что я пытаюсь сделать, используя иллюстрацию:

Это наши шахматы:

   ---------------------------
 |  1     2     3     4     5 |
 |  6     7     8     9    10 |
 | 11    12    13    14    15 |
 | 16    17    18    19    20 |
 | 21    22    23    24    25 |
   ---------------------------

И вот где находится наша королева: queen[2][3]

   ---------------------------
 |  1     2     3     4     5 |
 |  6     7     8     9    10 |
 | 11    12    13     ♙    15 |
 | 16    17    18    19    20 |
 | 21    22    23    24    25 |
   ---------------------------

Королева может атаковать все 8 направлений.Т.е.:

 horizontal(x2): 
   1. from queen position to left         : [13, 12, 11]
   2. from queen position to right        : [15]

 vertical(x2):
   1. from queen position to top          : [9, 4]
   2. from queen position to bottom       : [19, 24]

 diagonal(x2):
   1. from queen position to bottom-right : [20]
   2. from queen position to top-left     : [8, 2]

 diagonal(x2):
   1. from queen position to bottom-left  : [18, 22]
   2. from queen position to top-right    : [10]

Поскольку на этих 8 путях нет препятствий, королева может атаковать в общей сложности 14 атак.

Скажем, у нас есть некоторые препятствия:

   ---------------------------
 |  1     2     3     4     5 |
 |  6     7     x     9    10 |
 | 11     x    13     ♙    15 |
 | 16    17    18    19     x |
 | 21     x    23     x    25 |
   ---------------------------

Теперь королева может атаковать в общей сложности 7 атак: [13, 18, 19, 15, 10, 9, 4]

Код

MAXI = 10 ** 5

def queens_attack(size, number_of_obstacles, queen_pos, obstacles)
  # exit the function if...

  # size is negative or more than MAXI. Note MAXI has constraint shown in hackerrank
  return if size < 0 || size > MAXI

  # the obstacles is negative or more than the MAXI
  return if number_of_obstacles < 0 || number_of_obstacles > MAXI

  # the queen's position is outside of our chess dimension
  return if queen_pos[:row] < 1 || queen_pos[:row] > size
  return if queen_pos[:col] < 1 || queen_pos[:col] > size

  # the queen's pos is the same as one of the obstacles
  return if [[queen_pos[:row], queen_pos[:col]]] - obstacles == []

  row, col = queen_pos[:row], queen_pos[:col]

  # variable to increment how many places the queen can attack
  attacks = 0

  # the queen can attack on all directions:
  # horizontals, verticals and both diagonals. So let us create pointers
  # for each direction. Once the obstacle exists in the path, make the 
  # pointer[i] set to true
  pointers = Array.new(8, false)
  (1..size).lazy.each do |i|

    # this is the diagonal from queen's pos to bottom-right
    if row + i <= size && col + i <= size && !pointers[0]
      # set it to true if there is no obstacle in the current [row + i, col + i]
      pointers[0] = true unless [[row + i, col + i]] - obstacles != []
      # now we know the queen can attack this pos
      attacks += 1 unless pointers[0]
    end

    # this is diagonal from queen's pos to top-left
    if row - i > 0 && col - i > 0 && !pointers[1]
      # set it to true if there is no obstacle in the current [row - i, col - i]
      pointers[1] = true unless [[row - i, col - i]] - obstacles != []
      # now we know the queen can attack this pos
      attacks += 1 unless pointers[1]
    end

    # this is diagonal from queen's pos to bottom-left
    if row + i <= size && col - i > 0 && !pointers[2]
      pointers[2] = true unless [[row + i, col - i]] - obstacles != []
      attacks += 1 unless pointers[2]
    end

    # this is diagonal from queen's pos to top-right
    if row - i > 0 && col + i <= size && !pointers[3]
      pointers[3] = true unless [[row - i, col + i]] - obstacles != []
      attacks += 1 unless pointers[3]
    end

    # this is verticle from queen's pos to bottom
    if row + i <=size && !pointers[4]
      pointers[4] = true unless [[row + i, col]] - obstacles != []
      attacks += 1 unless pointers[4]
    end

    # this is verticle from queen's pos to top
    if row - i > 0 && !pointers[5]
      pointers[5] = true unless [[row - i, col]] - obstacles != []
      attacks += 1 unless pointers[5]
    end

    # this is horizontal from queen's pos to right
    if col + i <= size && !pointers[6]
      pointers[6] = true unless [[row, col + i]] - obstacles != []
      attacks += 1 unless pointers[6]
    end

    # this is horizontal from queen's pos to left
    if col - i > 0 && !pointers[7]
      pointers[7] = true unless [[row, col - i]] - obstacles != []
      attacks += 1 unless pointers[7]
    end
  end
  p attacks
end

Проблема

Теперь проблема в том, что я не знаю почемумой код делает ошибку тайм-аута от hackerrank.Я знаю это из-за контрольного примера, где размер шахмат может быть 10 000 х 10 000.Но не знаю, какое ограничение я пропускаю.

0 голосов
/ 26 октября 2018

Я только что узнал из комментария, опубликованного ОП, что я решил не ту проблему, несмотря на то, что вопрос ОП кажется достаточно ясным, особенно в примере, и согласуется с моей интерпретацией.Я оставлю это решение для следующей проблемы: «Если массив arr такой, что Matrix(*arr) является матрицей NxM, а расположение матрицы i,j, вернуть массив [d,a], где элементы d и a являются элементами на диагонали и антидиагональности, которые проходят через [d,a], но не включают в себя [d,a] и каждый из них поворачивается таким образом, чтобы индекс строки первого элемента был i+1, если i < arr.size-1, и 0, в противном случае.

В следующем подходе используются методы из класса Matrix .

Код

require 'matrix'

def diagonals(arr, row_idx, col_idx)      
  [diag(arr, row_idx, col_idx),
   diag(arr.map(&:reverse).transpose, arr.first.size-1-col_idx, row_idx)]
end

def diag(arr, row_idx, col_idx)
  nrows, ncols = arr.size, arr.first.size
  lr = [ncols-col_idx, nrows-row_idx].min - 1
  ul = [col_idx, row_idx].min
  m = Matrix[*arr]
  [*m.minor(row_idx+1,  lr, col_idx+1,  lr).each(:diagonal).to_a,
   *m.minor(row_idx-ul, ul, col_idx-ul, ul).each(:diagonal).to_a]
end

Пример

arr = [
  [ 1,  2,  3,  4,  5,  6,  7,  8,  9,  10],
  [11, 12, 13, 14, 15, 16, 17, 18, 19,  20],
  [21, 22, 23, 24, 25, 26, 27, 28, 29,  30],
  [31, 32, 33, 34, 35, 36, 37, 38, 39,  40],
  [41, 42, 43, 44, 45, 46, 47, 48, 49,  50],
  [51, 52, 53, 54, 55, 56, 57, 58, 59,  60],
  [61, 62, 63, 64, 65, 66, 67, 68, 69,  70],
  [71, 72, 73, 74, 75, 76, 77, 78, 79,  80],
  [81, 82, 83, 84, 85, 86, 87, 88, 89,  90],
  [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
]

diagonals arr, 4, 4
  #=> [[56, 67, 78, 89, 100, 1, 12, 23, 34], [54, 63, 72, 81, 9, 18, 27, 36]]
diagonals arr, 4, 5
  #=> [[57, 68, 79, 90, 2, 13, 24, 35], [55, 64, 73, 82, 91, 10, 19, 28, 37]]
diagonals arr, 0, 9
  #=> [[], [19, 28, 37, 46, 55, 64, 73, 82, 91]]

Объяснение

Предположим, что массив и местоположение цели были следующими.

arr = (1..30).each_slice(6).to_a
  #=> [[ 1,  2,  3,  4,  5,  6],
  #    [ 7,  8,  9, 10, 11, 12],
  #    [13, 14, 15, 16, 17, 18],
  #    [19, 20, 21, 22, 23, 24],
  #    [25, 26, 27, 28, 29, 30]]

row_idx = 2
col_idx = 3

Примечание arr[2][3] #=> 16. Получим диагональ с помощьюотрицательный наклон путем вычисления диагоналей двух младших матриц:

[[23, 24],
 [29, 30]]

и

[[2, 3],
 [8, 9]]

, что дает нам

[*[23, 30], *[2, 9]]
  #=> [23, 30, 2, 9]

Чтобы получить другую диагональ, мы вращаем массивпротив часовой стрелки на 90 градусов, отрегулируйте row_idx и col_idx и повторите описанную выше процедуру.

arr.map(&:reverse).transpose
  #=> [[6, 12, 18, 24, 30],
  #    [5, 11, 17, 23, 29],
  #    [4, 10, 16, 22, 28],
  #    [3,  9, 15, 21, 27],
  #    [2,  8, 14, 20, 26],
  #    [1,  7, 13, 19, 25]]

ncols = arr.first.size
  #=> 6
row_idx, col_idx = ncols-1-col_idx, row_idx
  #=> [2, 2]

Теперь мы извлекаем диагонали из младших матриц

[[21, 27],
 [20, 26]]

и

[[6, 12],
 [5, 11]]

, чтобы получить вторую диагональ:

[21, 26, 6, 11]
0 голосов
/ 25 октября 2018

Я применил логику, предоставленную @OmG.Не уверен, насколько это будет эффективно.

def stackOverflow(matrixSize, *args)
  pos, obstacles = *args
  chess = (1..(matrixSize * matrixSize)).each_slice(matrixSize).to_a
  obstacles.each do |l| chess[l[0]][l[1]] = '_' end
  row, col = pos[:row] - 1, pos[:col] - 1
  chess[row][col] = '♙'
  directions = [[],[],[],[],[],[],[],[]]

  (1...matrixSize).each do |l|
    directions[0] << chess[row + l][col + l] if (row + l) < matrixSize && (col + l) < chess_size
    directions[1] << chess[row - l][col - l] if (row - l) >= 0 && (col - l) >= 0
    directions[2] << chess[row + l][col - l] if (row + l) < matrixSize && (col - l) >= 0
    directions[3] << chess[row - l][col + l] if (row - l) >= 0 && (col + l) < matrixSize
    directions[4] << chess[row + l][col] if row + l < matrixSize
    directions[5] << chess[row - l][col] if row - l >= 0
    directions[6] << chess[row][col + l] if col + l < matrixSize
    directions[7] << chess[row][col - l] if col - l >= 0
  end
end

stackOverflow(5, 3, {row: 4, col: 3}, [[4,4],[3,1],[1,2]] )
0 голосов
/ 25 октября 2018

Я только что узнал из комментария, опубликованного ОП, что я решил не ту проблему, несмотря на то, что вопрос ОП кажется достаточно ясным, особенно в примере, и согласуется с моей интерпретацией.Я оставлю это решение для следующей проблемы: «Если массив arr такой, что Matrix(*arr) является матрицей NxM, а расположение матрицы i,j, вернуть массив [d,a], где элементы d и a являются элементами на диагонали и антидиагональности, которые проходят через [d,a], но не включают в себя [d,a] и каждый из них поворачивается таким образом, чтобы индекс строки первого элемента был i+1, если i < arr.size-1, и 0, в противном случае.

Код

def diagonals(arr, row_idx, col_idx) 
  ncols = arr.first.size
  sum_idx = row_idx+col_idx
  diff_idx = row_idx-col_idx
  a = Array.new(arr.size * arr.first.size) { |i| i.divmod(ncols) } -[[row_idx, col_idx]]
  [a.select { |r,c| r-c == diff_idx }, a.select { |r,c| r+c == sum_idx }].
    map do |b| b.sort_by { |r,_| [r > row_idx ? 0:1 , r] }.
      map { |r,c| arr[r][c] }
    end
end

Все элементы массива arr должны быть одинакового размера, но не требуется, чтобы arr.size = arr.first.size.

Пример

arr = [
  [ 1,  2,  3,  4,  5,  6,  7,  8,  9,  10],
  [11, 12, 13, 14, 15, 16, 17, 18, 19,  20],
  [21, 22, 23, 24, 25, 26, 27, 28, 29,  30],
  [31, 32, 33, 34, 35, 36, 37, 38, 39,  40],
  [41, 42, 43, 44, 45, 46, 47, 48, 49,  50],
  [51, 52, 53, 54, 55, 56, 57, 58, 59,  60],
  [61, 62, 63, 64, 65, 66, 67, 68, 69,  70],
  [71, 72, 73, 74, 75, 76, 77, 78, 79,  80],
  [81, 82, 83, 84, 85, 86, 87, 88, 89,  90],
  [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
]

diagonals(arr, 4, 4)
  #=> [[56, 67, 78, 89, 100, 1, 12, 23, 34],
  #    [54, 63, 72, 81, 9, 18, 27, 36]]

Объяснение

Предположим,

arr = (1..16).each_slice(4).to_a
  #=> [[ 1,  2,  3,  4],
  #    [ 5,  6,  7,  8],
  #    [ 9, 10, 11, 12],
  #    [13, 14, 15, 16]]

row_idx = 2
col_idx = 1

Шаги следующие.

a = Array.new(arr.size) { |i| Array.new(arr.first.size) { |j| [i,j] } }
  #=> [[[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]]]
ncols = arr.first.size
  #=> 4
sum_idx = row_idx+col_idx
  #=> 3
diff_idx = row_idx-col_idx
  #=> 1
a = Array.new(arr.size * arr.first.size) { |i| i.divmod(ncols) } - [[row_idx, col_idx]]
  #=> [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3],
  #    [2, 0], [2, 2], [2, 3], [3, 0], [3, 1], [3, 2], [3, 3]]

Выбор и сортировка местоположений [r, c] на диагонали сверху слева-вниз-справа, проходящей через [row_idx, col_idx].

b = a.select { |r,c| r-c == diff_idx }
  #=> [[1, 0], [3, 2]]
c = b.sort_by { |r,_| [r > row_idx ? 0:1 , r] }
  #=> [[3, 2], [1, 0]]

Выбор и сортировка местоположений [r, c] в правом верхнем углунижняя левая диагональ, проходящая через [row_idx, col_idx].

d = a.select { |r,c| r+c == sum_idx }
  #=> [[0, 3], [1, 2], [3, 0]]
e = d.sort_by { |r,c| [r > row_idx ? 0:1 , r] }
  #=> [[3, 0], [0, 3], [1, 2]]
[c, e].map { |f| f.map { |r,c| arr[r][c] }
  #=> [c, e].map { |f| f.map { |r,c| arr[r][c] } }
  #=> [[15, 5], [13, 4, 7]]
0 голосов
/ 24 октября 2018

Как правило, чтобы получить диагональные значения от i и j, вы можете перебирать i и j в то же время, пока одно из них не будет равно нулю.Следовательно, главная диагональ составляет от (i-1, j-1), (i-2, j-2), ... до i, j >= 0 и (i + 1, j + 1), (i +2, j + 2), ... до i, j <= n.Для антидиагональности это (i - 1, j + 1), (i - 2, j + 2), ... до i >= 0 и j <= n, (i + 1, j-1), (i + 2, j - 2), ... до i <= n и j >= 0.

...