Contexte
Considérons une chaîne (fermée) de tiges, dont chacune a une longueur entière. Combien de polyominos distincts sans trou pouvez-vous former avec une chaîne donnée? Ou en d'autres termes, combien de polygones différents non auto-entrecroisés avec des côtés alignés sur l'axe pouvez-vous former avec une chaîne donnée?
Regardons un exemple. Considérons une chaîne particulière composée de 8 tiges de longueur 1 et 2, que nous pouvons représenter comme [1, 1, 2, 2, 1, 1, 2, 2]
. Jusqu'à rotations et traductions, il n'y a que 8 polyominos possibles (on compte les réflexions différentes):
Cette première tige est bleu foncé, puis nous traversons le polygone dans le sens antihoraire .
Le sens de rotation n'affecte pas le résultat dans l'exemple ci-dessus. Mais considérons une autre chaîne [3, 1, 1, 1, 2, 1, 1]
, qui donne les 3 polyominos suivants:
Notez que nous ne reflet du dernier polyomino, car cela nécessiterait une traversée dans le sens horaire.
Si nous avions une chaîne plus flexible de la même longueur, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
nous serions en mesure de former les deux réflexions parmi d'autres polyoninoes, totalisant 9:
Le défi
Étant donné la description d'une chaîne, sous forme de tableau ou similaire, déterminez le nombre de polyominos distincts que vous pouvez former (jusqu'à rotations et traductions) en utilisant les tiges dans l'ordre tout en faisant le tour du périmètre dans le sens antihoraire.
Veuillez écrire un programme complet et inclure des commandes pour compiler (le cas échéant) et exécuter votre code à partir de la ligne de commande. Veuillez également inclure un lien vers un compilateur / interprète gratuit pour votre langue.
Votre programme devrait lire l'entrée de STDIN. La première ligne contient un nombre entier M . Les prochaines lignes M seront des cas de test, dont chacun sera une liste de longueurs de tige séparées par des espaces. Votre programme doit imprimer M lignes sur STDOUT, chacune étant constituée d'un seul entier - le nombre de polyominos distincts qui peuvent être formés.
Vous ne devez utiliser qu'un seul thread.
Votre programme ne doit pas utiliser plus de 1 Go de mémoire à la fois. (Ce n'est pas une limite complètement stricte, mais je surveillerai l'utilisation de la mémoire de votre exécutable et tuerai tout processus qui utilise régulièrement plus de 1 Go ou augmente considérablement au-dessus.)
Pour éviter des quantités excessives de pré-calcul, votre code ne doit pas dépasser 20 000 octets et vous ne devez lire aucun fichier.
Vous ne devez pas non plus optimiser en fonction des cas de test spécifiques choisis (par exemple en codant en dur leurs résultats). Si je soupçonne que vous le faites, je me réserve le droit de générer de nouveaux ensembles de référence. Les ensembles de tests sont aléatoires, donc les performances de votre programme sur celles-ci doivent être représentatives de ses performances sur des entrées arbitraires. La seule hypothèse que vous êtes autorisé à faire est que la somme des longueurs de tige est égale.
Notation
J'ai fourni des jeux de référence pour des chaînes de N = 10, 11, ..., 20 tiges. Chaque ensemble de test contient 50 chaînes aléatoires d'une longueur comprise entre 1 et 4 inclus.
Votre score principal est le plus grand N pour lequel votre programme termine l'ensemble de test complet dans les 5 minutes (sur ma machine, sous Windows 8). Le bris d'égalité sera le temps réel pris par votre programme sur cet ensemble de test.
Si quelqu'un bat le plus grand jeu de test, je continuerai à en ajouter de plus grands.
Cas de test
Vous pouvez utiliser les cas de test suivants pour vérifier l'exactitude de votre implémentation.
Input Output
1 1 0
1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1 1 1 9
1 1 1 1 1 1 1 1 1 1 1 1 36
1 1 1 1 1 1 1 1 1 1 1 1 1 1 157
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 758
1 1 2 2 1 1 2 2 8
1 1 2 2 1 1 2 2 1 1 23
1 1 2 2 1 1 2 2 1 1 2 2 69
1 2 1 2 1 2 1 2 3
1 2 1 2 1 2 1 2 1 2 1 2 37
1 2 3 2 1 2 3 2 5
1 2 3 2 1 2 3 2 1 2 3 2 23
3 1 1 1 2 1 1 3
1 2 3 4 5 6 7 1
1 2 3 4 5 6 7 8 3
1 2 3 4 5 6 7 8 9 10 11 5
2 1 5 3 3 2 3 3 4
4 1 6 5 6 3 1 4 2
3 5 3 5 1 4 1 1 3 5
1 4 3 2 2 5 5 4 6 4
4 1 3 2 1 2 3 3 1 4 18
1 1 1 1 1 2 3 3 2 1 24
3 1 4 1 2 2 1 1 2 4 1 2 107
2 4 2 4 2 2 3 4 2 4 2 3 114
Vous trouverez un fichier d'entrée avec ceux-ci ici .
Classement
User Language Max N Time taken (MM:SS:mmm)
1. feersum C++ 11 19 3:07:430
2. Sp3000 Python 3 18 2:30:181
la source
Réponses:
C ++ 11
Mises à jour: Ajout de la première ligne
c
qui éclate tôt si la distance est trop éloignée de l'origine (ce qui était tout le but de la variablerlen
, mais j'ai oublié de l'écrire dans la première version). Je l'ai changé pour utiliser beaucoup moins de mémoire, mais au prix du temps. Il résout maintenant N = 20 en un peu moins de 5 minutes pour moi.Compiler avec
la source
#define
thoPython 3 (avec PyPy ) - N = 18
Courez avec
./pypy <filename>
.Il s'agit de l'implémentation de référence que j'ai écrite lors de la discussion de la question avec Martin. Il n'a pas été conçu avec la vitesse à l'esprit et est assez hacky, mais il devrait fournir une bonne base de départ pour lancer les choses.
N = 18 prend environ 2,5 minutes sur mon modeste ordinateur portable.
Algorithme
Les rotations sont vérifiées en convertissant chaque forme en une série d'
F
avant,A
de virage dans le sens inverse des aiguilles d'une montre etC
de rotation dans le sens des aiguilles d'une montre à chaque point du réseau sur la limite de la forme - j'appelle cela une chaîne d'angle . Deux formes sont identiques en rotation si leurs chaînes angulaires sont des permutations cycliques. Plutôt que de toujours vérifier cela en comparant directement deux chaînes d'angles, lorsque nous trouvons une nouvelle forme, nous convertissons en une forme canonique avant de la stocker. Lorsque nous avons un nouveau candidat, nous nous convertissons à la forme canonique et vérifions si nous l'avons déjà (exploitant ainsi le hachage, plutôt que d'itérer à travers l'ensemble).La chaîne d'angle est également utilisée pour vérifier que la forme est formée dans le sens inverse des aiguilles d'une montre, en s'assurant que le nombre de
A
s dépasse le nombre deC
s par 4.L'auto-intersection est vérifiée naïvement en stockant chaque point de réseau sur la frontière de la forme et en voyant si un point est visité deux fois.
L'algorithme de base est simple, en plaçant la première tige vers la droite, puis en essayant toutes les possibilités pour les barres restantes. Si les tiges atteignent un point trop éloigné de l'origine (c'est-à-dire que la somme des longueurs de tige restantes est inférieure à la distance Manhattan du point depuis l'origine), alors nous arrêtons prématurément la recherche de ce sous-arbre.
Mises à jour (les plus récentes en premier)
la source