Порахуйте кількість сторін на багатокутнику


18

Порахуйте кількість сторін на багатокутнику

Робот, що рахує багатокутник, вирішив подорожувати світом, не розповідаючи нікому раніше, але дуже важливо, щоб процес підрахунку полігону не зупинявся занадто довго. Отже, у вас є наступне завдання: З огляду на чорно-біле зображення багатокутника, ваша програма / функтоїн повинна повертати кількість сторін.

Програма подаватиметься на старий комп'ютер з перфокарткою, а так як печкарди в наш час дуже дорогі, то краще спробуйте зробити свою програму якомога коротшою.

Краї мають довжину не менше 10 пікселів, а кути, утворені двома суміжними краями, принаймні 10 °, але не більше 170 ° (або знову більше 190 °). Полігон повністю міститься в зображенні, і багатокутник, і його доповнення пов'язані (немає ізольованих островів), тому цей вхід не буде дійсним:

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

Оцінка балів

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

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

Будь ласка, включіть загальну кількість у назву вашої заявки. (Загальна помилка - сума абсолютних різниць між реальною кількістю сторін та кожним висновком).

Тестові справи

n = 10

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

n = 36

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

n = 7

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

n = 5

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

Це не тестовий випадок, просто з цікавості: Скільки ребер ви отримаєте для цього вводу?

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


Я бачу багато кутів у ваших тестових випадках, які перевищують 170 °. Наприклад, усі «неточкові» кути (ті, що ближче до центру) у вашій зірці.
Дверна ручка

@Doorknob Це менший кут, який повинен бути менше 170 °.
lirtosiast

Так, але вони знову перевищують 190 °. Суть цього обмеження полягає у усуненні прикладів, коли дві суміжні сторони важко розрізнити.
flawr

2
Якого кольору інтер’єр багатокутника?
feersum

1
Програма подаватиметься на старий комп'ютер з перфокарткою, а так як печкарди в наш час дуже дорогі, краще спробуйте зробити свою програму якомога
коротшою

Відповіді:


12

Python 2 + PIL, без помилок, 313 307 байт

from Image import*
I=open(sys.argv[1])
w,h=I.size;D=I.getdata()
B={i%w+i/w*1j for i in range(w*h)if D[i]!=D[0]}
n=d=1;o=v=q=p=max(B,key=abs)
while p-w:
 p+=d*1j;e=2*({p}<B)+({p+d}<B)
 if e!=2:e%=2;d*=1j-e*2j;p-=d/1j**e
 if abs(p-q)>5:
    t=(q-v)*(p-q).conjugate();q=p;w=o
    if.98*abs(t)>t.real:n+=1;v=p
print n

Знімає ім'я файлу зображення в командному рядку та друкує результат на STDOUT.

Дає правильний результат для всіх тестів, а n = 28 для кола.

Пояснення

Алгоритм працює, проходячи по периметру багатокутника і підраховуючи кількість зустрічаються вершин (виявляються як зміни напрямку). Ми починаємо з пікселя, віддаленого від початку, oякий гарантовано є вершиною, а отже, прилягає до краю (тобто межі між пікселем переднього плану та фоновим пікселем). Ми відслідковуємо свою позицію, pостанню вершину vта останню "контрольну точку" q, всі вони спочатку рівні o. Ми також стежимо за напрямком краю d, щодо поточного пікселя; dспочатку вказує на схід, що є безпечним напрямком, оскільки ми знаємо, що є край на схід відo інакше він не був би найдалі від початку. Рухаємось по краю, у напрямку, перпендикулярному доd такого, якийdвказує зліва, тобто за годинниковою стрілкою. Щоразу, коли ми «падаємо з краю», тобто в будь-якій ситуації, де pзнаходиться поза полігоном, або де піксель зліва від нас (тобто у напрямку до d) знаходиться всередині полігону, ми регулюємось pі dвідповідно до відновлення.

Кожен раз, коли відстань між pі останньою контрольною точкою qстає більшою за 5, ми намагаємося визначити, чи ми пройшли вершину між qі p: Ми порівнюємо кут між vq(тобто вектором від vдо q), який є загальним напрямком сторони полігону, по якому ми йшли, коли дійшли до останньої контрольної точки, і . Ми продовжуємо таким чином, поки не повернемось до початкової точки та не повернемо кількість знайдених вершин (зауважте, що кількість вершин спочатку 1, оскільки початкова точка,qp переміщення між останньою контрольною точкою та поточною позицією. Якщо кут більший приблизно на 10 °, то робимо висновок, що ми йдемо по іншій стороні багатокутника, збільшуємо кількість вершин і встановлюємоv поточну вершину на p. На кожній контрольній точці, незалежно від того, виявили ми вершину чи ні, ми оновлюємосьq останню контрольну точку доpoo сама по собі є вершиною).

Зображення нижче показують виявлені вершини. Зауважимо, що прийняття pпоточного положення в кожній контрольній точці як положення нової вершини не є оптимальним, оскільки справжня вершина, ймовірно, знаходиться десь між останньою контрольною точкою q, та pпо периметру. Як бачимо, всі вершини, крім першої (як правило, нижня права вершина) трохи відключені. Виправлення цього коштуватиме більше байтів, але, здається, це працює досить добре. Незважаючи на це, важко не переборщити лише чотири тестові справи.

n = 10 n = 36 n = 7 n = 5 Коло


Дякую за детальне пояснення! Я люблю ваші ілюстрації!
flawr

Якщо є край на схід від o, чи не буде інший кінець ще далі від початку?
aditsu

1
@aditsu Я думаю, що термінологія тут може бути трохи заплутаною. Ми говоримо про сторони багатокутника, в геометричному сенсі, і ребра (набору пікселів, що містять) багатокутника, як растрової графіки. oє найдальшим пікселем переднього плану від початку, тому піксель на його сході повинен бути фоновим пікселем, отже, ми говоримо, що є край на схід від o.
Ел
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.