Lors de la résolution de problèmes de programmation compétitifs, j'avais parfois besoin de ** créer et traiter des états pour chaque cas, plutôt que de simplement compter le nombre de cas. Dans Ruby, [ʻArray # combination](https://docs.ruby-lang.org/ja/latest/method/Array/i/combination.html) et [ʻArray # repeat_permutation
](https: // docs.ruby-lang.org/ja/latest/method/Array/i/repeated_permutation.html) etc. sont disponibles, mais quand je veux autre chose, je ne peux pas l'assembler rapidement et cela prend du temps.
Je vais donc essayer de faire la méthode que je voulais à ce moment-là, également en tant que pratique.
Il y a des moments où vous voulez ** couvrir des modèles qui sont inclus / non inclus pour chaque élément, par exemple lorsque vous voulez les résoudre tous en même temps. Le nombre de cas est "2 ** ary.size".
Le nombre d'éléments peut être de «0» à «ary.size », vous pouvez donc lister les combinaisons pour chacun. C'est facile et ** c'est rapide car l'essentiel du traitement est laissé à l'implémentation interne de Ruby **.
each_subset.rb
def each_subset(ary, &block)
0.upto(ary.size) { |n| ary.combination(n, &block) }
end
if $0 == __FILE__
each_subset([*0..2]) { |subset| p subset }
end
output
[]
[0]
[1]
[2]
[0, 1]
[0, 2]
[1, 2]
[0, 1, 2]
Essayons de faire l'ordre d'énumération «k» (à partir de 0) en notation binaire que «1» «0» correspond à l'inclusion / exclusion de chaque élément tel quel.
Si vous le faites docilement, cela ressemble à ceci. Ruby obtient la valeur du bit ʻiavec [ʻInteger # []
](https://docs.ruby-lang.org/ja/latest/method/Integer/i/=5b=5d.html) ça peut.
each_subset.rb
def each_subset(ary, &block)
(1 << ary.size).times do |k|
subset = ary.select.with_index { |_, i| k[i] == 1 }
block.call(subset)
end
end
if $0 == __FILE__
each_subset([*0..2]) { |subset| p subset }
end
output
[]
[0]
[1]
[0, 1]
[2]
[0, 2]
[1, 2]
[0, 1, 2]
Puisque le premier élément «0» de «ary »correspond au bit le moins significatif (= pair / impair), la présence / absence est commutée à chaque fois, tandis que le dernier élément« 2 »correspond au bit le plus significatif, il n'est donc figé que dans la seconde moitié. Il apparaît.
Comme vous pouvez le voir, l'implémentation est une double boucle avec un nombre fixe de fois, et le temps de calcul est O (2 N </ sup> N). 2 A partir de N </ sup>, N n'est pas un gros problème, il ne devrait donc pas y avoir de problème d'utilisation pratique (le nombre d'éléments est d'environ 16). Si quoi que ce soit, je suis plus préoccupé par le fait que j'évalue simplement avec # select
.
Essayez O (2 N </ sup>) pour le moment. Implémentez-le récursivement et déposez-le dans le processus quand il y en a un de moins.
each_subset.rb
def each_subset(ary, selected = [], &block)
if ary.empty?
block.call(selected.dup) #Dupliquer car c'est trop dangereux si le tableau est le même objet
return
end
ary = ary.dup #Dupliquer pour ne pas interrompre la séquence d'entrée
elem = ary.pop
each_subset(ary, selected, &block) #n'inclut pas d'élem
selected.unshift(elem)
each_subset(ary, selected, &block) #Y compris elem
selected.shift
# ary << elem #Non requis si dupliqué
return #Renvoie nul pour le moment
end
if $0 == __FILE__
each_subset([*0..2]) { |subset| p subset }
end
Version non récursive, et enregistre en interne tous les modèles dans un tableau avant de s'exécuter (car c'est facile).
each_subset.rb
def each_subset(ary, &block)
subsets = [[]]
ary.each do |elem|
subsets.concat(subsets.map { |ss| [*ss, elem] })
end
return subsets.each(&block)
end
if $0 == __FILE__
each_subset([*0..2]) { |subset| p subset }
end
-->
Pour ʻary = [0, 1, 2, 3, 4] , je veux créer, par exemple,
[[0, 1], [2], [3, 4]] `.
D'un point de vue différent, le nombre de cas est 2 ** (ary.size -1)
car cela signifie qu '"un délimiteur est inséré / non inséré pour ** entre ** éléments du tableau". Puisqu'il s'agit d'un mystère de ce qu'il faut renvoyer lorsqu'il s'agit d'un tableau vide, faites-en une forme pratique pour l'implémentation.
Ceci est également implémenté de manière récursive. Si vous groupez et extrayez certains de ʻary`, vous pouvez créer un autre groupe avec les autres.
each_split.rb
def each_split(ary, selected = [], &block)
if ary.empty?
block.call(selected.map(&:dup)) #Dupliquer car c'est trop dangereux si le tableau est le même objet
return
end
# ary == part1 +Opérer pour garder part2
part1 = []
part2 = ary.dup #Dupliquer pour ne pas interrompre la séquence d'entrée
selected << part1
until part2.empty?
part1 << part2.shift #Déplacer la position de division vers la droite
each_split(part2, selected, &block)
end
selected.pop
# ary.replace(part1) #Non requis si dupliqué
return #Renvoie nul pour le moment
end
if $0 == __FILE__
each_split([*0..4]) { |sp| p sp }
end
output
[[0], [1], [2], [3], [4]]
[[0], [1], [2], [3, 4]]
[[0], [1], [2, 3], [4]]
[[0], [1], [2, 3, 4]]
[[0], [1, 2], [3], [4]]
[[0], [1, 2], [3, 4]]
[[0], [1, 2, 3], [4]]
[[0], [1, 2, 3, 4]]
[[0, 1], [2], [3], [4]]
[[0, 1], [2], [3, 4]]
[[0, 1], [2, 3], [4]]
[[0, 1], [2, 3, 4]]
[[0, 1, 2], [3], [4]]
[[0, 1, 2], [3, 4]]
[[0, 1, 2, 3], [4]]
[[0, 1, 2, 3, 4]]
Recommended Posts