Кількість отворів у багатокутнику


11

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

Вхідний список Lз nточок на площині , а також список Tз 3-кортежів з елементами з 0...n-1. Для кожного елемента в Tкортежі (t_1,t_2,t_3)представлені три вершини (зі списку L) трикутника в тріангуляції. Зауважте, що це тріангуляція у значенні "трикутник багатокутника" , тому Tщо у цьому перекритті ніколи не буде двох трикутників . Додатковим умовою є те, що вам не доведеться санітувати введення даних Lі Tне містити повторів.

Приклад 1 : Якщо L = {{0,0},{1,0},{0,1},{1,2}}і T = {{0,1,2},{1,2,3}}тоді вказаний многокутник має кількість отворів 0.

Фігура 1

Приклад 2 : Якщо L = {{0,0},{1,0},{2,0},{2,1},{2,2},{1,2},{0,2},{0,1},{.5,.5},{1.5,.5},{1.5,1.5},{.5,1.5}}і T = {{5,6,11},{5,10,11},{4,5,10},{3,8,10},{2,3,9},{2,8,9},{1,2,8},{0,1,8},{0,8,11},{0,7,11},{6,7,11},{3,4,10}}тоді вхід полігона повинен призвести до виходу 2.

Малюнок 2

Завдання полягає в тому, щоб написати найкоротшу програму (або функцію), яка приймає Lі Tвводить і повертає кількість отворів. "Переможець" буде визнаний записом із найменшим числом символів (орієнтовна дата закінчення 1 червня).

Формат введення зразка (зверніть увагу на індексацію 0):

0,0
1,0
0,1
1,2
0,1,2
1,2,3    

1
"З'єднання багатокутника гарантується умовою, що кожен трикутник у вхідній тріангуляції ділить принаймні 1 сторону з іншим трикутником." -- ні. Це недостатня умова. Візьмемо, наприклад, T=1,2,3/1,2,4/5,6,7/5,6,8. Кожен трикутник розділяє ребро з іншим трикутником, але триангуляція відключена
Джон Дворак

Чи можемо ми вважати, що вхід представляє дійсну часткову тріангуляцію (два трикутники не перетинаються і жоден трикутник не присутній двічі), і триангуляція пов'язана?
Джон Дворак


Чи можемо ми також припустити, що вхід пов'язаний краєм, в тому сенсі, що неможливо видалити скінченний набір точок, щоб зробити форму від’єднаною? (напр .: T=1,2,3/1,4,5підключено, але не підключено до краю)
Іван Дворак

2
Я не впевнений, чому цей бізнес щодо дат закінчення розпочався останнім часом. Вам дозволяється змінити прийняту відповідь, тому не потрібно встановлювати дату закінчення. Доцільно думати про те, що ви зачекаєте тиждень, перш ніж вибрати відповідь, щоб не налякати людей на думку, що перша відповідь є неперевершеною, але поки ви активно на сайті, ви можете змінити обрану відповідь. якщо хтось опублікує кращий. Відповідні мета-дискусії включають meta.codegolf.stackexchange.com/q/542/194 та meta.codegolf.stackexchange.com/q/193/194
Пітер Тейлор

Відповіді:


5

GolfScript (23 символи)

~.{2*2/~}%{$}%.&,@@+,-)

Передбачає формат введення, використовуючи позначення масиву GolfScript і цитують (або цілісні) координати. Напр

$ golfscript codegolf11738.gs <<<END
[["0" "0"] ["1" "0"] ["2" "0"] ["2" "1"] ["2" "2"] ["1" "2"] ["0" "2"] ["0" "1"] [".5" ".5"] ["1.5" ".5"] ["1.5" "1.5"] [".5" "1.5"]] [[5 6 11] [5 10 11] [4 5 10] [3 8 10] [2 3 9] [2 8 9] [1 2 8] [0 1 8] [0 8 11] [0 7 11] [6 7 11] [3 4 10]]
END
2

( Інтернет-еквівалент )

або

$ golfscript codegolf11738.gs <<<END
[[0 0] [1 0] [0 1] [1 2]] [[0 1 2] [1 2 3]]
END
0

( Інтернет-еквівалент )


5

Пітона, 71

Далі йде програма (не функція ), яка обчислює потрібне число.

len(set().union(*(map(frozenset,zip(t,t[1:]+t))for t in T)))-len(L+T)+1

Приклад використання:

>>> L = ((0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,1),(.5,.5),(1.5,.5),(1.5,1.5),(.5,1.5))
>>> T = ((5,6,11),(5,10,11),(4,5,10),(3,8,10),(2,3,9),(2,8,9),(1,2,8),(0,1,8),(0,8,11),(0,7,11),(6,7,11),(3,4,10))
>>> len(set().union(*(map(frozenset,zip(t,t[1:]+t))for t in T)))-len(L+T)+1
2

+1 для використання бризки, використання замороженого набору замість сортування, zip (не можу сказати, що я його колись використовував, потрібно ознайомитись.)
Kaya

3

APL, 36

{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}

Функція приймає Lяк лівий аргумент і Tяк його правий.

Наприклад:

      L←(0 0)(1 0)(0 1)(1 2)
      T←(0 1 2)(1 2 3)
      L{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}T
0
      L←(0 0)(1 0)(2 0)(2 1)(2 2)(1 2)(0 2)(0 1)(.5 .5)(1.5 .5)(1.5 1.5)(.5 1.5)
      T←(5 6 11)(5 10 11)(4 5 10)(3 8 10)(2 3 9)(2 8 9)(1 2 8)(0 1 8)(0 8 11)(0 7 11)(6 7 11)(3 4 10)
      L{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}T
2

Пояснення, рухаючись справа наліво:

  • ⍴⍺,⍵з'єднує два вхідні вектори і повертає їх довжину ( V + F)
  • Крок всередину наступного блоку:
    • ¨⍵ застосовує функцію зліва до кожного елемента правого аргументу і повертає результат
    • ⍵,⍵ повертає правильний аргумент, з'єднаний з самим собою
    • 3 2⍴формує векторний аргумент на три пари. У цьому випадку вона поєднує разом перший і другий, третій і перший, а також другий і третій елементи вектора.
    • ,/ з'єднує векторний аргумент разом
    • ⍵[⍋⍵] сортує правильний аргумент
    • ∪/ фільтрує будь-які дублікати
    • ⍴⊃ перетворює вкладений скаляр у вектор, і він повертає його довжину.
    • Вся функція повертає кількість ребер у формі ( E)
  • 1 зрозуміла (я сподіваюся, що ...)

Потім вся функція повертається 1+E-(V+F), або 1-(F+V-E).


Дуже точно те, що робить моє рішення GolfScript. Я здивований, що це набагато довше, ніж GolfScript.
Пітер Тейлор

@PeterTaylor Я був здивований, що рішення GolfScript було набагато коротшим! (Але знову ж , це є GolfScript)
Волатильність

2

Mathematica, 93 (ще не так багато гольфу)

f[l_, t_] :=  Max@MorphologicalComponents[Erosion[Graphics[
                                                        GraphicsComplex[l, Polygon[t + 1]]], 1]] - 1

(Простіри додані для наочності)

Тестування:

f[{{0, 0}, {1, 0}, {0, 1}, {1, 2}}, {{0, 1, 2}, {1, 2, 3}}]
(*
 -> 0
*)

{l, t} = {{{0, 0}, {1,   0}, {2,    0}, {2,     1}, {2,    2}, {1, 2}, {0, 2}, 
           {0, 1}, {.5, .5}, {1.5, .5}, {1.5, 1.5}, {.5, 1.5}}, 

           {{5, 6, 11}, {5, 10, 11}, {4, 5, 10}, {3, 8, 10}, {2, 3,  9}, 
            {2, 8,  9}, {1,  2,  8}, {0, 1,  8}, {0, 8, 11}, {0, 7, 11}, {6, 7, 11}, {3, 4, 10}}};
f[l, t]
 (*
  -> 2
 *)

Чи не покладається це на трикутники чи отвори, що мають певний мінімальний розмір (аргумент Erosion)?
Джон Дворак

@JanDvorak Можливо, я помиляюся, але я думаю, що якщо ви не використовуєте нескінченну арифметику точності, будь-яке рішення буде працювати, поки ви не досягнете певного мінімального розміру (вам доведеться вирішити, вирівняні три точки чи ні). Просто в такому вирішенні проблема прямо вказана.
Доктор Белісарій

якщо ви використовуєте топологічний підхід, вам не доведеться. Якщо колінеарний три точки, то вам потрібен трикутник нульової площі там - інакше у вас є отвір.
Джон Дворак

@belisarius. Ось відповідь, яку я отримав від служби технічної підтримки Wolfram про невідповідність наших результатів: "Привіт - Дякую за електронну пошту. Я підтвердив, що ваш код дає різні результати на Mac і Windows. Я не думаю, що це призначене поведінка, тому Я подав звіт з нашими розробниками з цього питання. Я обов'язково передаю будь-яку корисну інформацію, яку я отримаю від наших розробників з цього питання. Будь ласка, повідомте мене, якщо у вас є додаткові питання ... Технічна підтримка Wolfram Research , Inc. "
DavidC

@DavidCarraher "Так, у мене є додаткові запитання. Ви
Доктор Белісарій

2

Рубі, 239 символів (227 корпус)

def f t
e=t.flat_map{|x|x.permutation(2).to_a}.group_by{|x|x}.select{|_,x|x.one?}.keys
n=Hash[e]
(u,n=n,n.dup;e.map{|x|a,b=*x;n[a]=n[n[a]]=n[b]})until n==u
n.values.uniq.size+e.group_by(&:last).map{|_,x|x.size}.reduce(-1){|x,y|x+y/2-1}
end

зауважте, що я розглядаю лише топологію. Я жодним чином не використовую позиції вершин.

абонент (очікує T у форматі Mathematica або JSON):

input = gets.chomp
input.gsub! "{", "["
input.gsub! "}", "]"
f eval(input)

Тест:

f [[0,1,2],[1,2,3]]
#=> 0
f [[5, 6, 11], [5, 10, 11], [4, 5, 10], [3, 8, 10], [2, 3, 9], [2, 8, 9], [1, 2, 8], [0, 1, 8], [0, 8, 11], [0, 7, 11], [6, 7, 11], [3, 4, 10]]
#=> 2
f [[1,2,3],[3,4,5],[5,6,1],[2,3,4],[4,5,6],[6,1,2]]
#=> 1

Так, характерний підхід еулера. Ось як я це зробив у пітоні.
Кая

2
@Kaya. (Див. Яйце Колумба en.wikipedia.org/wiki/Egg_of_Columbus ) Після того, як хтось дав ейлерову відповідь на ваше запитання, ймовірність того, що інші дотримуватимуться, значно збільшується. Я можу запевнити, що набагато складніше та приємніше відкрити підхід самостійно, лише після цього підключившись до роботи Ейлера з багатогранниками.
DavidC

2

Математика 76 73 72 67 62

Після довгих експериментів я зрозумів, що точне розташування вершин не викликає занепокоєння, тому я представляв проблему з графіками. Основні інваріанти, кількість трикутників, ребер і вершин залишалися інваріантними (за умови уникнення перетину ліній).

У графі було два типи внутрішніх «трикутників»: ті, мабуть, були обличчям, тобто «заповненим» трикутником, і ті, де їх не було. Кількість внутрішніх граней не мала жодного відношення до країв або вершин. Це означало, що пробивання дірок у повністю «заповнених» графіках лише зменшило кількість облич. Я систематично грав з варіаціями серед трикутників, відстежуючи грані, вершини та краї. Врешті-решт я зрозумів, що кількість отворів завжди дорівнює 1 - #face - # vertices + #edges. Це виявилося 1 мінусом характеристики Ейлера (про який я знав лише в контексті регулярних багатогранників (хоча довжина ребер явно не мала значення).

Функція нижче повертає кількість отворів при введенні вершин і трикутників. На відміну від мого попереднього подання, він не покладається на сканування зображення. Ви можете розглядати це як 1 - характеристику Ейлера, тобто 1 - (F + V -E), де F= #face, V= # вершини, E= # ребра. Функція повертає кількість отворів, 1 - (F + V -E)враховуючи фактичні грані (трикутники) і вершини.

Неважко показати, що видалення будь-якого трикутника на зовнішній стороні комплексу не впливає на характеристику Ейлера, незалежно від того, поділяє він одну чи дві сторони з іншими трикутниками.

Примітка: vзамість Lпочаткової рецептури буде використано нижній регістр ; тобто він містить самі вершини (не V, кількість вершин)

fвикористовується для Tвихідної рецептури; тобто він містить трикутники, представлені як упорядкована трійка вершинних індексів.

Код

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&

(Дякуємо містеру Чарівникові за бриття 5 символів, усунувши правило заміни.)


Приклад 1

v = {{0, 0}, {1, 0}, {0, 1}, {1, 2}}; f = {{0, 1, 2}, {1, 2, 3}};

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&[v, f]

0

Нульові дірки.


Приклад 2

v = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1} , {.5, .5}, {1.5, .5}, {1.5, 1.5}, {.5, 1.5}}; f = {{5, 6, 11}, {5, 10, 11}, {4, 5, 10}, {3, 8, 10}, {2, 3, 9}, {2, 8, 9} , {1, 2, 8}, {0, 1, 8}, {0, 8, 11}, {0, 7, 11}, {6, 7, 11}, {3, 4, 10}};

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&[v, f]

2

Таким чином, 2 отвори є в прикладі 2.


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

1
ваш другий приклад повертає 0 тут (тому я цього не використовував MorphologicalEulerNumber[]). Mma 9.01, Win XP.
Доктор Белісарій

Я також використовую 9.0.1, але на Mac. Ви говорите, що Mathematica повертає іншу відповідь від моєї в Windows? Якщо це так, це звучить як помилка (у версії Windows XP).
DavidC


@Jan Dvorak. MorphologicalEulerNumberіноді вимагає зображення; він відмовляється приймати графічний об’єкт. У цих випадках розмір отвору та роздільна здатність є критичними (див. Codegolf.stackexchange.com/questions/8706/… ). Але тут він працює безпосередньо з об’єктом Graphics, який явно містить усі вершини. Я уявляв (або сподівався), що він використовуватиме підхід, який не залежить від образу. Я б хотів, щоб я знав, як він намагався вирішити питання. Можливо, якесь вимовляння у вихідному коді для функції уточнить речі.
DavidC

1

Пітона, 107

Я зрозумів, що безпосередньо брати пари було коротше, ніж from itertools import*і набирати текст combinations(). Але я також помітив, що моє рішення спиралося на вхідні трикутні грані, що мають вершини, перелічені в послідовному порядку. Тому кількість прибутків у характері не така вже й велика.

f=lambda l,t:1-len(l+t)+len(set([tuple(sorted(m))for n in[[i[:2],i[1:],[i[0],i[2]]]for i in t]for m in n]))

Пітона, 115

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

from itertools import*
f=lambda l,t:1-len(l+t)+len(set([m for n in[list(combinations(i,2)) for i in t]for m in n]))

Приклад використання:

> f([[0,0],[1,0],[0,1],[1,2]],[[0,1,2],[1,2,3]])
> 0
> f([[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[.5,.5],[1.5,.5],[1.5,1.5],[.5,1.5]],[[5,6,11],[5,10,11],[4,5,10],[3,8,10],[2,3,9],[2,8,9],[1,2,8],[0,1,8],[0,8,11],[0,7,11],[6,7,11],[3,4,10]])
> 2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.