J'essaie de montrer à mon fils comment le codage peut être utilisé pour résoudre un problème posé par un jeu et voir comment R gère les mégadonnées. Le jeu en question s'appelle "Lucky 26". Dans ce jeu, les numéros (1-12 sans doublons) sont positionnés sur 12 points sur une étoile de david (6 vertex, 6 intersections) et les 6 lignes de 4 numéros doivent toutes s'ajouter à 26. Sur environ 479 millions de possibilités (12P12 ), il existe apparemment 144 solutions. J'ai essayé de coder cela en R comme suit, mais la mémoire est un problème, semble-t-il. J'apprécierais grandement tout conseil pour faire avancer la réponse si les membres ont le temps. Remerciant les membres à l'avance.
library(gtools)
x=c()
elements <- 12
for (i in 1:elements)
{
x[i]<-i
}
soln=c()
y<-permutations(n=elements,r=elements,v=x)
j<-nrow(y)
for (i in 1:j)
{
L1 <- y[i,1] + y[i,3] + y[i,6] + y[i,8]
L2 <- y[i,1] + y[i,4] + y[i,7] + y[i,11]
L3 <- y[i,8] + y[i,9] + y[i,10] + y[i,11]
L4 <- y[i,2] + y[i,3] + y[i,4] + y[i,5]
L5 <- y[i,2] + y[i,6] + y[i,9] + y[i,12]
L6 <- y[i,5] + y[i,7] + y[i,10] + y[i,12]
soln[i] <- (L1 == 26)&(L2 == 26)&(L3 == 26)&(L4 == 26)&(L5 == 26)&(L6 == 26)
}
z<-which(soln)
z
r
bigdata
permutation
DesertProject
la source
la source
x<- 1:elements
et plus important encoreL1 <- y[,1] + y[,3] + y[,6] + y[,8]
. Cela n'aiderait pas vraiment votre problème de mémoire, vous pouvez donc toujours regarder dans rcpprm(list=ls())
votre MRE. Si quelqu'un copie-colle dans une session active, il peut perdre ses propres données.Réponses:
Voici une autre approche. Il est basé sur un article de blog MathWorks de Cleve Moler , l'auteur du premier MATLAB.
Dans l'article de blog, pour économiser de la mémoire, l'auteur ne permute que 10 éléments, en conservant le premier élément comme élément apex et le 7ème comme élément de base. Par conséquent, seules les
10! == 3628800
permutations doivent être testées.Dans le code ci-dessous,
1
à10
. Il y en a un total10! == 3628800
.11
l'élément apex et maintenez-le fixe. Peu importe où commencent les affectations, les autres éléments seront dans les bonnes positions relatives .for
boucle.Cela devrait produire la plupart des solutions, donner ou prendre des rotations et des réflexions. Mais cela ne garantit pas que les solutions sont uniques. Il est également assez rapide.
la source
Il existe en fait 960 solutions. Ci-dessous, nous utilisons
Rcpp
,RcppAlgos
* et leparallel
package pour obtenir la solution en un peu plus de6 seconds
4 cœurs. Même si vous choisissez d'utiliser une approche à thread unique avec des R de baselapply
, la solution est renvoyée en environ 25 secondes.Tout d'abord, nous écrivons un algorithme simple
C++
qui vérifie une permutation particulière. Vous remarquerez que nous utilisons un tableau pour stocker les six lignes. Ceci est pour les performances car nous utilisons la mémoire cache plus efficacement que l'utilisation de 6 baies individuelles. Vous devrez également garder à l'esprit que l'C++
indexation basée sur zéro est utilisée.Maintenant, en utilisant les arguments
lower
etupper
danspermuteGeneral
, nous pouvons générer des blocs de permutations et les tester individuellement pour contrôler la mémoire. Ci-dessous, j'ai choisi de tester environ 4,7 millions de permutations à la fois. La sortie donne les indices lexicographiques des permutations de 12! de telle sorte que la condition Lucky 26 soit satisfaite.Maintenant, nous vérifions l'utilisation
permuteSample
et l'argumentsampleVec
qui vous permet de générer des permutations spécifiques (par exemple, si vous passez 1, cela vous donnera la première permutation (ie1:12
)).Enfin, nous vérifions notre solution avec la base R
rowSums
:* Je suis l'auteur de
RcppAlgos
la source
Pour les permutations, rcppalgos est génial. Malheureusement, il y a 479 millions de possibilités avec 12 champs, ce qui signifie que cela prend trop de mémoire pour la plupart des gens:
Il existe quelques alternatives.
Prenez un échantillon des permutations. Ce qui signifie, ne faites que 1 million au lieu de 479 millions. Pour ce faire, vous pouvez utiliser
permuteSample(12, 12, n = 1e6)
. Voir la réponse de @ JosephWood pour une approche quelque peu similaire, sauf qu'il échantillonne jusqu'à 479 millions de permutations;)Construisez une boucle dans rcpp pour évaluer la permutation à la création. Cela économise de la mémoire car vous finiriez par créer la fonction pour ne renvoyer que les résultats corrects.
Abordez le problème avec un algorithme différent. Je vais me concentrer sur cette option.
Nouvel algorithme avec contraintes
Les segments doivent être 26
Nous savons que chaque segment de ligne dans l'étoile ci-dessus doit totaliser jusqu'à 26. Nous pouvons ajouter cette contrainte pour générer nos permutations - ne nous donnez que des combinaisons qui totalisent jusqu'à 26:
ABCD et EFGHGroupes
Dans l'étoile ci-dessus, j'ai coloré trois groupes différemment: ABCD , EFGH et IJLK . Les deux premiers groupes n'ont pas non plus de points communs et sont également des segments d'intérêt en ligne. Par conséquent, nous pouvons ajouter une autre contrainte: pour les combinaisons totalisant jusqu'à 26, nous devons nous assurer que ABCD et EFGH ne se chevauchent pas. IJLK se verra attribuer les 4 numéros restants.
Permutez à travers les groupes
Nous devons trouver toutes les permutations de chaque groupe. Autrement dit, nous n'avons que des combinaisons qui totalisent jusqu'à 26. Par exemple, nous devons prendre
1, 2, 11, 12
et faire1, 2, 12, 11; 1, 12, 2, 11; ...
.Calculs finaux
La dernière étape consiste à faire le calcul. J'utilise
lapply()
etReduce()
ici pour faire une programmation plus fonctionnelle - sinon, beaucoup de code serait tapé six fois. Voir la solution d'origine pour une explication plus approfondie du code mathématique.Échange ABCD et EFGH
À la fin du code ci-dessus, j'ai profité du fait que nous pouvons échanger
ABCD
etEFGH
obtenir les permutations restantes. Voici le code pour confirmer que oui, nous pouvons échanger les deux groupes et être correct:Performance
Au final, nous n'avons évalué que 1,3 million des 479 permutations et seulement mélangé sur 550 Mo de RAM. Il faut environ 0,7 secondes pour fonctionner
la source
Voici la solution pour le petit gars:
la source