Предположение
Нам дан массив arr
размера n
, каждый элемент является массивом размера m
. Мы sh создадим другой массив n x m
, a
, такой что каждый элемент a[i][j]
равен 1
(иначе 0
), если все следующие массивы не пустые:
a[i] & a[i] # non-empty if a is non-empty
a[i] & a[(i+1)%n]
a[(i+1)%n] & a[(i+2)%n]
a[(j-1)%n] & a[j]
Это то, что я понимаю как «переходный». Обратите внимание, что я предположил, что переходное отношение «оборачивается» от последнего к первому элементу arr
.
Давайте рассмотрим пример.
arr = [["A", "B", "C"],
["A", "D", "E"],
["D", "E", "F"]]
Предположим, что мы будем sh для вычисления a[i][j]
массива a
, который создается. Это равняется 1
(иначе 0
), если все следующие массивы не пустые:
a[1] & a[1] #=> a[1] => ["A", "D", "E"]
a[1] & a[2%3] #=> a[1] & a[2] => ["D"]
a[(i+1)%n] & a[(i+2)%n] #=> a[2] & a[1] => []
Обратите внимание, что имеет (a[1] & a[2%3]).empty? #=> true
, нет необходимости вычислять третье выражение (или любое другое следующие выражения, если arr
были больше).
Для i #=> 0
,
a[0,0] = (arr[0] & arr[0]).any?
#=> arr[0].any? #=> true, hence = 1
a[0,1] = (arr[0] & arr[1]).any?
#=> ["A"].any? #=> true, hence = 1
a[0,2] = (arr[0] & arr[1]).any? && (arr[1] & arr[2]).any?
#=> (a[0,1] == 1) && ["D"].any? => true && true => true, hence = 1
Для i #=> 1
,
a[1,1] = (arr[1] & arr[1]).any?
#=> arr[1].any? #=> true, hence = 1
a[1,2] = (arr[1] & arr[2]).any?
#=> ["D"].any? #=> true, hence = 1
a[1,0] = (arr[1] & arr[2]).any? && (arr[2] & arr[0]).any?
#=> (a[1,2] == 1) && [].any? => true && false => true, hence = 0
Для i #=> 2
,
a[2,2] = (arr[2] & arr[2]).any?
#=> arr[2].any? #=> true, hence = 1
a[2,0] = (arr[2] & arr[0]).any?
#=> [].any? #=> false, hence = 0
a[2,1] = (arr[2] & arr[0]).any? && (arr[0] & arr[1]).any?
#=> (a[2,0] == 1) && ["A"].any? => false && true => false, hence = 0
Код
require 'set'
def transitive(arr)
n = arr.size
st = n.times.with_object(Set.new) do |i,st|
(i..i+n-1).each do |j|
if j==i
st << [i,j]
else
jj = j % n
jprev = (j-1) % n
break unless st.include?([i,jprev]) & (arr[jprev] & arr[jj]).any?
st << [i,jj]
end
end
end
Array.new(n) do |i|
Array.new(arr.first.size) { |j| st.include?([i,j]) ? 1 : 0 }
end
end
Пример
Для arr
, определенного ранее,
transitive(arr)
#=> [[1, 1, 1],
# [0, 1, 1],
# [0, 0, 1]]
Пояснение
Шаги следующие:
n = arr.size
#=> 3
st = n.times.with_object(Set.new) do |i,st|
(i..i+n-1).each do |j|
if j==i
st << [i,j]
else
jj = j % n
jprev = (j-1) % n
break unless st.include?([i,jprev]) & (arr[jprev] & arr[jj]).any?
st << [i,jj]
end
end
end
#=> #<Set: {[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]}>
st
- это набор переходных элементов arr
. Это показывает, что элементы arr
с индексами [0, 2]
(порядок имеет значение) являются переходными, а элементы с индексами [2, 0]
- нет (поскольку st
не содержит [2, 0]
). Обратите внимание, что как только [2, 0]
было определено, что оно не является транзитивным, нет необходимости проверять [2, 1]
.
На последнем шаге используется метод Array :: new :
Array.new(n) {|i| Array.new(arr.first.size) {|j| st.include?([i,j]) ? 1 : 0}}
#=> [[1, 1, 1],
# [0, 1, 1],
# [0, 0, 1]]