C'est le golf de code. Le gagnant est le code valide avec le plus petit nombre d'octets.
Défi
Étant donné les entrées M et N , la largeur et la hauteur d'une grille rectangulaire de carrés, sortez un polygone qui satisfait les éléments suivants:
- Les arêtes du polygone sont constituées uniquement d'arêtes carrées: il n'y a pas d'arêtes diagonales - toutes sont verticales ou horizontales.
- Le polygone n'a pas de trous: chaque carré à l'extérieur du polygone peut être atteint par des pas orthogonaux sur des carrés à l'extérieur du polygone, à partir d'un carré à l'extérieur du polygone sur la limite extérieure du rectangle.
- Le polygone n'a pas d'auto-intersection: des arêtes carrées se rencontrant au sommet, pas plus de 2 peuvent faire partie du périmètre du polygone.
- Le polygone est connecté: tout carré du polygone doit être accessible à partir de tout autre carré du polygone via des étapes orthogonales qui restent à l'intérieur du polygone.
- Le polygone a le périmètre maximum possible: selon la formule ci-dessous.
Votre code doit fonctionner pour M et N de 1 à 255.
Formule pour le périmètre maximum
Le défi ici est de trouver le plus golfable de ces polygones avec le périmètre maximum. Le périmètre maximal lui-même est toujours défini par la formule:
Cela est vrai car pour un périmètre maximum, chaque sommet carré doit être sur le périmètre. Pour un nombre impair de sommets, cela n'est pas possible et le meilleur qui peut être atteint est un sommet de moins (puisque le périmètre est toujours pair).
Production
Sortez la forme sous la forme d'une chaîne de caractères séparés par un saut de ligne ( N lignes d'exactement M caractères). Ici, j'utilise l'espace pour les carrés à l'extérieur du polygone et '#' pour les carrés à l'intérieur du polygone, mais vous pouvez utiliser deux caractères visuellement distincts, à condition que leur signification soit cohérente pour toutes les entrées.
Vous pouvez inclure jusqu'à une nouvelle ligne de début et jusqu'à une nouvelle ligne de fin.
Si vous le souhaitez, vous pouvez produire à la place M lignes d'exactement N caractères, et vous pouvez choisir la sortie M par N pour certaines entrées et N par la sortie M pour d'autres.
Exemples
Invalide en raison d'un trou:
###
# #
###
Invalide en raison de l'intersection (toucher en diagonale - un sommet avec 4 bords carrés sur le périmètre) et, accessoirement, d'un trou:
##
# #
###
Non valide en raison de la déconnexion:
#
# #
#
Polygone valide de périmètre maximal:
# #
# #
###
Crédits
Au début, j'ai sous-estimé la vitesse à laquelle la valeur du périmètre maximum pouvait être calculée, et j'allais simplement demander cette valeur comme sortie. Merci aux personnes merveilleusement utiles dans le chat pour avoir expliqué comment déterminer le périmètre maximal pour N et M arbitraires et contribué à en faire un défi qui durera plus d'une réponse ...
Plus précisément grâce à:
Sparr , Zgarb , feersum , jimmy23013 .
Réponses:
CJam, 47 octets
Essayez-le en ligne
Explication:
Il y a deux cas principaux pour le résultat. Si au moins une des tailles est impaire, le motif est un simple "râteau". Par exemple, pour la saisie
7 6
:Si les deux tailles sont égales, il y a une colonne supplémentaire où chaque deuxième carré est "activé". Par exemple, pour la saisie
8 6
:Maintenant, pour montrer que ces modèles atteignent le maximum théorique du périmètre comme indiqué dans la description du problème, nous devons confirmer que le premier modèle a un périmètre
(M + 1) * (N + 1)
et le second la même valeur moins 1.Pour le premier motif, nous avons pour le périmètre, avec
M
une dimension impaire:M
pour le bord supérieur.2
sur le côté de la rangée supérieure.(M - 1) / 2
pour les espaces entre les dents.(M + 1) / 2
dents avec périmètre2 * (N - 1) + 1
chacune.Cela revient à:
Pour le deuxième cas où les deux
M
etN
sont pairs, le périmètre s'additionne à partir de:M
pour le bord supérieur.2
sur le côté de la rangée supérieure.M / 2
pour le # ouvert dans la rangée du haut.M / 2
dents avec périmètre2 * (N - 1) + 1
chacune pour les dents plates.2 * (N / 2 - 1)
périmètre supplémentaire pour les dents.En ajoutant tout cela ensemble:
la source
Ruby, Rév.1, 66
Utilisé
m
pour augmenter la puissance 0 o 1 pour décider si 1 oum
#
les caractères seront imprimés.Utilisé
>
pour tester la dernière ligne au lieu de==
.Impossible de se débarrasser de l'espace après les puts, ni des supports!
Ruby, Rév 0, 69
Il s'agit d'une fonction lambda anonyme. Utilisez-le comme ceci:
Finalement, après avoir demandé si M et N pouvaient être échangés, je n'en avais pas besoin.
Sorties typiques pour N impair. Si nous supprimons le
#
sur le côté droit, nous aurons clairement (N + 1) (M + 1). Les inclure pour joindre la forme supprime 2 carrés de périmètre horizontal et ajoute 2 carrés de périmètre vertical, il n'y a donc pas de changement.Ici, nous nous appuyons sur l'expression
"#"*(i%2==0?m:1)
pour donner des rangées alternées de M#
symboles et un#
symbole, et justifier à droite à M caractères.Sorties typiques pour N pair.
5 6
a clairement le même périmètre que6 5
, ou un incrément de M + 1 = 6 par rapport à l'5 5
ajout de périmètre vertical en raison de la crénulation de la rangée inférieure.6 6
a la même chose que6 5
plus un incrément de (M + 1) -1 = 6 dans le périmètre vertical. Ils sont donc conformes à la formule.Il est très pratique que Ruby
rjust
vous permette de spécifier le remplissage à utiliser pour les cellules vides. Normalement, le rembourrage est réglé sur" "
mais pour la dernière ligne, nous passons à"# "
(notez que le remplissage ne sera nécessaire que sur la dernière ligne si N est pair. Où N est impair, la dernière ligne sera complète et il n'y aura pas de justification, donc vous ne verra pas les créneaux.)Vérifiez le ici.
la source
i%2==0
pouri%2<1
enregistrer un octet (je l' ai fait ce changement à la liaison ideone).#
rembourrage pour la dernière rangée? Par exemple, dans la toute dernière figure, le périmètre n'est-il pas le même sans le#
coin inférieur droit?#
simplement parce que c'est déjà ainsi que chaque ligne se termine, donc c'est moins d'octets que d'y mettre un espace. (Je ne connais pas le rubis cependant ...)."# "
pas" #"
dû au fait que ce dernier donnerait 2 adjacents#
pour un M impair ce qui n'est certainement pas souhaité. 2 adjacent#
même pour M ne fait pas de mal, donc je suis allé avec cela. Je n'ai pas essayéljust
, il peut être possible de le faire plus proprement avec cela, mais il ne serait pas si évident que j'imprime exactement M caractères par ligne.C,
10997 octets et preuve d'exactitudeJ'écrivais ma solution mais @steveverrill m'a battu. J'ai pensé que je partagerais tout de même, car j'ai inclus une preuve d'exactitude pour la stratégie utilisée.
Code réduit:
Avant réduction:
Stratégie et preuve:
En supposant l'exactitude de l'équation du périmètre maximal (M + 1) (N + 1) - ((M + 1) (N + 1)) mod 2 , ce qui suit explique la stratégie optimale utilisée et prouve son exactitude par induction:
Pour un M impair, nous dessinons une forme semblable à une main avec M / 2 + 1 doigts, par exemple:
Nous prouvons maintenant que cette stratégie est optimale pour tout M impair par induction:
Cas de base: M = N = 1
La cellule unique est remplie. La solution est correcte puisque (1 + 1) * (1 + 1) = 2 * 2 = 4, et un carré a 4 côtés.
Induction sur la largeur:
Supposons que la stratégie de la forme de la main fonctionne pour (N, M-2) où M est impair, c'est-à-dire que son périmètre est optimal et est (N + 1) (M - 2 + 1) + ((M -1) (N + 1)) mod 2 . Nous montrons maintenant que cela fonctionnera pour (N, M) .
Le processus d'ajout d'un doigt supprime un bord du polygone et ajoute 3 + 2N . Par exemple:
En combinant cela avec notre hypothèse que le périmètre précédent était optimal, le nouveau périmètre est:
Puisque nous avons affaire à l'arithmétique modulo 2,
Ainsi, prouver que l'augmentation de la largeur en ajoutant des doigts conduit à un périmètre optimal.
Induction sur la hauteur:
Supposons que la stratégie de la forme de la main fonctionne pour (N-1, M) , où M est impair, c'est-à-dire que son périmètre est optimal et est N (M + 1) + ((M + 1) N) mod 2 . Nous montrons maintenant que cela fonctionnera pour (N, M) .
L'augmentation de la hauteur de la main ne fait qu'allonger les doigts, situés au premier et à tous les autres index x. Pour chaque augmentation de hauteur, chaque doigt ajoute deux au périmètre, et il y a (M + 1) / 2 doigts, donc, une augmentation de N entraîne une augmentation de 2 (M + 1) / 2 = M + 1 dans le périmètre.
En combinant cela avec l'hypothèse, nous avons que le nouveau périmètre est:
L'arithmétique modulaire nous permet de simplifier le dernier terme, pour obtenir:
Prouver que la solution est optimale pour tout N> 0 et impair M> 0.
Pour M même, nous remplissons le tableau de la même manière que pour M impair, mais nous ajoutons des créneaux au dernier segment, par exemple:
Nous prouvons maintenant que cette stratégie est optimale.
Induction pour même M:
Supposons que la solution est correcte pour (N, M-1), avec M-1 impair (comme cela a été prouvé dans le dernier cas), qui a un périmètre optimal de (N + 1) M - ( M (N + 1)) mod 2 . Nous montrons maintenant que cela fonctionnera pour (N, M).
Comme pour augmenter les doigts, chaque créneau ajoute deux au périmètre du polygone. Le nombre total de créneaux est (N + N mod 2) / 2 , pour un total de N + N mod 2 périmètre ajouté.
En combinant cela avec l'hypothèse, nous avons que le nouveau périmètre est:
Nous avons ça
Parce que si N est impair, cela se réduit à 0 = 0, et si N est pair, il se réduit à
Ainsi, la stratégie est optimale pour tout M, N> 0 .
la source