Пакувальні кола


21

Погляньте на це зображення. Зокрема, як влаштовані отвори на торцях.

введіть тут опис зображення

( Джерело зображення )

Зверніть увагу, як труби на цьому зображенні упаковані в шестикутний візерунок. Відомо, що в 2D шестикутна решітка - це найгустіша упаковка кіл. У цьому виклику ми зупинимося на тому, щоб мінімізувати периметр упаковки кіл. Один корисний спосіб візуалізації периметра - це уявити прокладку навколо колекції гумок.

Завдання

Подавши ціле додатне ціле число n, покажіть колекцію nкіл, упаковану якомога щільніше.

Правила та уточнення

  • Припустимо, кола мають діаметр 1 одиницю.
  • Мінлива бути зведена до мінімуму довжина периметра, який визначений , щоб бути опуклою оболонкою з центрів кіл в групі. Погляньте на це зображення:

введіть тут опис зображення

Три кола по прямій лінії мають периметр 4 (опуклий корпус - прямокутник 2х0, а 2 рахуються двічі), розташовані під кутом 120 градусів мають периметр приблизно 3,85, а трикутник має периметр всього 3 одиниці. Зауважте, що я ігнорую додаткові пі-одиниці, який би був фактичний периметр, тому що я дивлюся лише на центри кіл, а не їхні краї.

  • Можливо (і майже напевно буде) безліч рішень для будь-якої заданої n. Ви можете випустити будь-яке з них на свій розсуд. Орієнтація не має значення.
  • Кола повинні бути на шестикутній решітці.
  • Кола повинні бути діаметром не менше 10 пікселів і можуть бути заповненими чи ні.
  • Ви можете написати або програму, або функцію.
  • Вхід може бути прийнятий через STDIN, як аргумент функції, або найближчий еквівалент.
  • Вихід може бути відображений або виведений у файл.

Приклади

Нижче я маю приклади дійсних та недійсних результатів для n від 1 до 10 (дійсні приклади лише для перших п'яти). Дійсні приклади знаходяться зліва; кожен приклад праворуч має більший периметр, ніж відповідний дійсний приклад.

введіть тут опис зображення

Велике спасибі Steveverrill за допомогу в написанні цього виклику. Щаслива упаковка!


3
Чекаю на Гексагоні, я ставлю на облік. ; D
Аддісон Крим

@VoteToClose: Я не думаю, що шестикутник має графічний вихід, але MAN, це було б приголомшливо!
El'endia Starman

@ El'endiaStarman Ну, ти можеш написати SVG до stdout, але я не думаю, що я збираюся ...: P
Martin Ender

1
Нічого собі, ніхто раніше не дякував мені сміливо за мої коментарі в пісочниці. Я червонію :-D Звичайно, я прокоментував це, оскільки мені сподобався виклик, хоча я не впевнений, чи не встигну я відповісти на нього.
Річка Рівня Св.

Згідно з моєю дискусією з Рето Кораді на відповідь користувача81655, я думаю, що найбільший шестикутник, який ми побачимо з гострими кутами, - це довжина бічної сторони 7d (8 кіл.) Це всього N = 169 кіл. Ви можете розглянути питання про обмеження проблеми цим числом, що дасть більше шансів отримати правильну відповідь (на даний момент їх немає) та мати можливість перевірити. З іншого боку, може бути цікавіше залишити проблему відкритою для довільної Н.
Річка Рівня Св.

Відповіді:


4

Mathematica 295 950 байт

Примітка. Ця версія, яка ще залишається гольфу, стосується проблем, порушених Стівом Мерріллом щодо моїх попередніх спроб.

Хоча це вдосконалення в порівнянні з першою версією, він не знайде найгустішої конфігурації ручки, де можна було б шукати кругову, а не шестикутну загальну форму.

Він знаходить рішення, будуючи повний внутрішній шестикутник (при n> = 6, а потім вивчає всі конфігурації для завершення зовнішньої оболонки з рештоюючими колами.

Цікаво, що, як зазначав Світ Меррілл у коментарях, рішення для n+1кіл не завжди складається з рішення для n кіл з доданим іншим колом. Порівняйте поданий розв’язок для 30 кіл із заданим рішенням для 31 кола. (Примітка. Є унікальне рішення для 30 кіл.)

m[pts_]:={Show[ConvexHullMesh[pts],Graphics[{Point/@pts,Circle[#,1/2]&/@ pts}], 
ImageSize->Tiny,PlotLabel->qRow[{Length[pts],"  circles"}]],
RegionMeasure[RegionBoundary[ConvexHullMesh[pts]]]};
nPoints = ((#+1)^3-#^3)&;pointsAtLevelJ[0] = {{0,0}};
pointsAtLevelJ[j_]:=RotateLeft@DeleteDuplicates@Flatten[Subdivide[#1, #2, j] &@@@
Partition[Append[(w=Table[j{Cos[k Pi/3],Sin[k Pi/3]},{k,0,5}]), 
w[[1]]], 2, 1], 1];nPointsAtLevelJ[j_] := Length[pointsAtLevelJ[j]]
getNPoints[n_] := Module[{level = 0, pts = {}},While[nPoints[level]<=n, 
pts=Join[pointsAtLevelJ[level],pts];level++];Join[Take[pointsAtLevelJ[level],n-Length[pts]],
pts]];ns={1,7,19,37,61,91};getLevel[n_]:=Position[Union@Append[ns,n],n][[1, 1]]-1;
getBaseN[n_] := ns[[getLevel[n]]];pack[1]=Graphics[{Point[{0,0}], Circle[{0, 0}, 1/2]}, 
ImageSize->Tiny];pack[n_]:=Quiet@Module[{base = getNPoints[getBaseN[n]], 
outerRing = pointsAtLevelJ[getLevel[n]], ss},ss=Subsets[outerRing,{n-getBaseN[n]}];
SortBy[m[Join[base,#]]&/@ss,Last][[1]]]

Деякі з перевірок передбачали порівняння понад ста тисяч випадків для одного значення n (включаючи симетрії). Щоб запустити загальну кількість 34 тестових випадків, знадобилося приблизно 5 хвилин. Потрібно сказати, що при більшій n'sмірі цей підхід грубої сили скоро виявиться непрактичним. Напевно, існують більш ефективні підходи.

Цифри праворуч від кожної упаковки - це периметри відповідних синіх опуклих корпусів. Нижче наведено вихід для 3 < n < 35. Червоні кола - це ті, які додаються навколо звичайного шестикутника.

диски



1
Як я вже згадував у відповіді користувача 81655, виступаюче одиночне коло на 22 (і 17, 25, 28, 31, 34) краще розмістити в середині ряду кіл, на яких він сидить.
Рівень річки Св.

Я теж так думав, але потім зазначив, що 9, у якого також виступає коло, вважався правильним. Коли у мене з’явиться певний час, я порівняю вимірювання опуклих корпусів (центрів).
DavidC

у 9 виступаюче коло - або 1/4, або 3/4 вздовж плоского ряду, тому це не має ніякої різниці. у 17, 22, 25, 28, 31 виступаюче коло - 1/6, 3/6 або 5/6 вздовж, тому середнє положення краще (подумайте про те, щоб тягнути струну набік: простіше витягнути з середини, тому що так що струна має менше розширення. У 34 (і 35) ми маємо 1/8, 3/8, 5/8 і 7/8 вздовж плоскої сторони. Тому для цього нам слід вибрати 3/8 і 5/8 до 1/8 та 7/8.
Рівень річки Св.

Ви абсолютно праві, і це підтверджується вимірюваннями.
DavidC

Це круто! Перехід 30-> 31 показує, що ми не можемо просто прийняти попередню форму і додати коло назовні (це дало б периметр 16.464.) Також є принаймні один випадок, коли ви могли б просто додати одне коло зовні, але вибрав інше розташування: 12-> 13
рівень річки Св.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.