Веселий геримандерінг


26

Фон

У Сполучених Штатах є унікальна любов до геримандерінгу - до навмисних маніпуляцій виборчим округом для прогнозування певних результатів голосування. Нещодавно перед Верховним Судом була порушена справа про загрозу родовищ . Геррімандерінг, особливо коли він пов'язаний з расою, визнається незаконним і призводить до вимоги переробити районні лінії.

Давши прямокутну карту муніципалітету (масив 2d), ви намалюєте районні лінії, щоб допомогти вашій партії отримати найбільше представництво. Тобто ви будете геримандер. Кожна громада має дві партії, 0і 1. Карта буде складатися з квадратів з 0або 1на них. Ось приклад карти:

Виклик

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

Вхідні дані

Вхід складається з карти, кількості округів для малювання та мінімальної кількості округів, які 1партія повинна виграти (мінімальний бал).

Вихідні дані

Виходом буде карта районів. Кожен район буде унікально складений з великої літери алфавіту. Так, це означає, що не буде більше 26 районів.

Якщо немає можливого результату, коли введена сторона виграє достатньо округів, будь-який:

  1. Роздрукувати "Ми спробували ..."
  2. Фатальна помилка, оскільки партія отримала непоправні пошкодження за результатами виборів
  3. Або і те й інше

Правила (також дуже важливо)

  1. Усі райони повинні бути суміжними
  2. Округи можуть не мати в них інших округів
  3. Кожен район повинен мати принаймні чотири вузли в ньому. Введення буде відповідати правилам, тобто number_of_districts * 4на карті буде принаймні вузли
  4. Оцінка кожної партії - це кількість округів, у яких вона має більшість
  5. Якщо округ має однакову кількість 0s і 1s, то жодна зі сторін від цього не має вигоди
  6. Нормальні правила без обману
  7. Це , тому найкоротший код у байтах виграє.

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

1. Input       1. Output       2. Input       2. Output     3. Input      3. Output
districts: 5   Image and map   districts: 3   Image below   districts: 3  fatal error
min wins: 3                    min wins: 3                  min wins: 3
map:                           map:                         map:
00000110000    AAAAAAAAAAA     101101                       101101
10000010000    AAAAAAAAAAA     100000                       100000
10010000011    AAAAAAAAAAA     011011                       011011
11001110000    BBBBBBBAAAA     111111                       100111
00111111000    BBBBBBBAAAA     
01111111000    CCCCCDDDAAA     
01111111001    CCCCCDDDAAA     
01000111100    EEEEEDDDDDD     
00000001000    EEEEEDDDDDD     

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


@Arnauld, так, вони лише показові. Реальний вихід повинен бути таким, як у першому тестовому випадку з літерами алфавіту. Я змінив тег, щоб це відобразити.
Даніель

Простий розділ першого тестового випадку буде приблизно таким . Це правильно?
Арнольд

@Arnauld, так, це дійсно.
Даніель

Отже, для 3-го прикладу, якби ми поділили його на горизонтальні ряди, кожен 1 округ висотою, то 1-і виграли б 3 на 1 так?
Майкл Дорган

3
Це нагадує мені чимало того, що потрібно було зробити для графіки на основі графіки на портативних комп'ютерах Nintendo від DMG до DS. Вам надали конкретні фігури для вирізання графіки і довелося мінімізувати кількість використовуваних фігур, оскільки ви могли використовувати лише апаратно визначене число спрайтів (фігур). Це була непроста проблема.
Michael Dorgan

Відповіді:


6

R , 938 896 858 952 байт

function(N,M,m){U="We tried...
"
L=length
A=matrix
W=which
K=sum
S=sample
G=unique
H=function(s,p=s-1){Y=S(c(s-j,s+j,p*(p%%j>0),(s+1)*(s%%j>0)))
Y[Y>0&Y<=k]}
C=function(v,z=W(r==v))K(z%%j<2,z-j<0,(z+j)>k)
m=A(strsplit(m,"")[[1]],1)
i=W(m<0)[1]-1
m=((t(A(m,i+1))[,1:i]>0)-.5)*2
if((K(m)<M&(N-M)<1)|K(m>0)<(3*M))cat(U) else{j=max(1,nrow(m))
k=i*j;w=g=T
while(w<9&g){Z=R=N;Q=M;b=0
r=A(0,j,i)
while(b<9&g){s=W(r<1)
s=s[S(L(s))][1:min(L(s),R)]
r[s]=1:L(s);a=0
while(K(r<1)>0&a<(k^2)){a=a+1
s=S(W(r>0&r<=R),1);p=r[s]
Y=H(s)
Y=Y[r[Y]<1]
if(L(Y)){Y=Y[order(m[Y])]
if(K(m[r==p]>1))r[Y[1]]=p else r[Y[L(Y)]]=p}}
if(a<(k^2)){for(v in 1:R){if(K(m[r==v])>0){r[r==v]=max(k,max(r))+1
Q=Q-1;Z=Z-1}}
if(Q<1){g=F
for(v in 1:R)r[r==v]=max(k,max(r))+1
for(v in G(c(r)))g=g|(K(r==v)<4)|(L(G(r[H(W(r==v))]))+C(v))<3}}
b=b+1;r[r<=R]=0;R=Z}
w=w+1}
if(g)cat(U) else{u=G(c(r))
for(v in 1:L(u))r[r==u[v]]=v
cat(paste(apply(A(LETTERS[r],j,i),1,paste,collapse=""),collapse="
"))}}}

Спробуйте в Інтернеті!

Масивний > 900 > 800 (ні!)> 900 байт. Код працює наступним чином. Нехай N - кількість виборчих округів, а M - мінімальна кількість округів, де 1 бажає мати більшість.

По-перше, код випадковим чином призначає N округів різним групам. Далі він випадковим чином розширює їх, тобто додає район до випадково вибраної групи, гарантуючи, що округ знаходиться поруч з округом, який уже належить до цієї групи. У процесі розширення він надає перевагу округу з 1 більшістю, якщо окружна група ще не є повною 1 більшістю; якщо в групі вже є певна більшість, тоді вона надає перевагу району 0. Це триває, поки не будуть призначені всі округи.

Кожна група, де є більшість для 1 партії, зберігається, а її округи блокуються. Якщо є принаймні M групи з більшістю 1, то все добре, і ми можемо роздрукувати результат, ми можемо перевірити, чи є принаймні 4 округи в кожній групі. Якщо буде досягнуто обрізання 4 округів, ми можемо з радістю надрукувати результат. В іншому випадку код намагається перепризначити райони, які не заблоковані на стільки доступних груп, тобто N - # збережених груп.

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

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

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


Чи можете ви видалити будь-які нові рядки?
NoOneIsHere

Я зробив. Я також призначив більші імена функцій для однієї літери і замінив декілька ==0на, <1коли змінна була суворо цілою і додатною.
NofP

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

1
858 байтів - "звичайні" гольфи, очищення використання дужок із if...elseзаявами, заміна cна них as.vector, зміна "\n"буквальними новими рядками та використання факту, який >автоматично примушує цифри до символів мовчки та порівнюватиме їх кодові точки. Напевно, є ще якісь гольфи, які я зробив, яких не пам'ятаю, але це початок. Я думаю, що ми можемо підправити ще кілька речей, але я не на 100% впевнений, що розумію код ...
Джузеппе

Хороший! Я взяв натхнення. Порівнюючи ваш код, я також виявив помилку в шахті, яка іноді може призвести до дуже малих районних груп (менше 4 округів). Зараз це виправлено.
NofP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.