Jolly gerrymandering


26

sfondo

Gli Stati Uniti hanno un amore unico per la gerrymandering - la deliberata manipolazione di un distretto elettorale per prevedere determinati risultati di voto. Proprio di recente c'è stato un caso gerrymandering portato davanti alla Corte Suprema. Il gerrymandering, specialmente se legato alla razza, è dichiarato illegale e comporta l'obbligo di ridisegnare le linee distrettuali.

Data una mappa rettangolare di un comune (2d array), traccerai delle linee distrettuali per aiutare il tuo gruppo a ottenere la maggior rappresentazione. Cioè, farai il gerrymander. Ogni comune ha due parti 0e 1. La mappa sarà composta da quadrati con uno 0o 1su di essi. Ecco una mappa di esempio:

Sfida

Raggrupperai la mappa in distretti in modo che la 1parte ottenga almeno il numero di distretti specificato dall'Input.

Ingresso

L'input consisterà in una mappa, il numero di distretti da disegnare e il numero minimo di distretti che il 1partito deve vincere (il punteggio minimo).

Produzione

L'output sarà una mappa dei distretti. Ogni distretto sarà composto in modo univoco da una lettera maiuscola dell'alfabeto. Sì, questo significa che non ci saranno più di 26 distretti.

Se non è possibile alcun output in cui la parte immessa vince abbastanza distretti, sia:

  1. Stampa "Abbiamo provato ..."
  2. Errore fatale perché il partito è stato irrimediabilmente ferito dai risultati delle elezioni
  3. O entrambi

Regole (anche molto importanti)

  1. Tutti i distretti devono essere contigui
  2. I distretti potrebbero non avere altri distretti in essi
  3. Ogni distretto deve contenere almeno quattro nodi. L'input sarà coerente con le regole, il che significa che ci saranno almeno number_of_districts * 4nodi nella mappa
  4. Il punteggio di ciascuna parte è il numero di distretti in cui ha la maggioranza
  5. Se un distretto ha lo stesso numero di 0s ed 1S, né benefici partito da esso
  6. Regole normali senza barare
  7. Questo è , quindi vince il codice più breve in byte.

Casi test

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     

Naturalmente, il tuo programma dovrebbe funzionare per qualsiasi caso di test valido, non solo per questi.


@Arnauld, sì, sono solo illustrativi. Il risultato reale dovrebbe essere come nel primo caso di test con le lettere dell'alfabeto. Ho cambiato il tag per riflettere questo.
Daniel,

Una semplice partizione del primo caso di test sarebbe qualcosa del genere . È corretto?
Arnauld,

@Arnauld, sì, è valido.
Daniel,

Quindi, per il terzo esempio, se lo dividessimo in file orizzontali, ciascuna alta 1 distretto, gli 1 vincerebbero 3 a 1 sì?
Michael Dorgan,

3
Questo mi ricorda molto di cosa si doveva fare per la grafica basata sui caratteri sui palmari Nintendo da DMG a DS. Ti sono state assegnate forme specifiche per tagliare la grafica e hai dovuto ridurre al minimo il numero di forme utilizzate in quanto potevi avere solo un numero definito di hardware di sprite (forme) in uso. Non è stato un problema facile.
Michael Dorgan,

Risposte:


6

R , 938 896 858 952 byte

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="
"))}}}

Provalo online!

Una soluzione massiccia > 900 > 800 (no!)> 900 byte. Il codice funziona come segue. Sia N il numero di distretti elettorali e M il numero minimo di distretto in cui 1 desidera avere la maggioranza.

Innanzitutto, il codice assegna casualmente N distretti a diversi gruppi. Successivamente, li espande casualmente, cioè aggiunge un distretto a un gruppo selezionato casualmente, assicurando che il distretto sia vicino a un distretto già appartenente a quel gruppo. Nel processo di espansione, dà la precedenza a un distretto con una maggioranza di 1, se il gruppo distrettuale non è ancora una maggioranza completa di 1; se il gruppo ha già una certa maggioranza, dà la precedenza a un distretto 0. Continua fino a quando tutti i distretti non sono stati assegnati.

Ogni gruppo in cui è presente la maggioranza per 1 parte viene archiviato e i suoi distretti sono bloccati. Se ci sono almeno M gruppi con una maggioranza di 1, allora tutto va bene e possiamo stampare il risultato e possiamo controllare se ci sono almeno 4 distretti in ciascun gruppo. Se viene raggiunto il limite di 4 distretti, possiamo felicemente stampare il risultato. Altrimenti, il codice tenta di riassegnare i distretti che non sono bloccati su tutti i gruppi disponibili, ovvero N - # gruppi memorizzati.

I codici ci provano più volte (9 volte). Se fallisce, reimposta tutto e ricomincia. Lo fa per altre 9 volte prima di rinunciare e stampare "abbiamo provato ...".

Se il codice inizialmente non riesce, riprovare più volte. Ho regolato il numero di ripetizioni in modo che possa essere eseguito in TIO in meno di un minuto. Tuttavia, se esiste una soluzione, questo codice può (eventualmente) trovarla. La parte di casualità dell'algoritmo fornisce una probabilità diversa da zero che, se esiste una soluzione, può trovarla. Il numero limitato di prove è l'unico fattore limitante per il successo.

EDIT: aggiunto il controllo che nessun gruppo distrettuale può essere completamente circondato solo da un altro gruppo, a meno che il gruppo distrettuale non abbia distretti ai margini di una determinata piazza. Penso che all'inizio mi mancasse.


Puoi rimuovere eventuali newline?
NoOneIsHere

L'ho fatto. Ho anche assegnato nomi di funzione più lunghi a singole lettere e ne ho sostituiti alcuni ==0con <1quando la variabile era strettamente intera e positiva.
NofP

1
Ci sono un sacco di cose qui che possono essere banalmente giocate a golf, ma questo è un buon primo tentativo di risposta, quindi +1, e suggerirò di modificarle un paio d'ore una volta che non sono sul mio telefono!
Giuseppe,

1
858 byte - Golfs "normali", ripulendo l'uso di parentesi graffe con if...elsele dichiarazioni, scambiando cper as.vector, cambiando "\n"con a capo letterali, e sfruttando il fatto che >verrà automaticamente numeri costringere a personaggi silenziosamente e confrontare i loro codepoints. Probabilmente ci sono alcuni altri golf che ho fatto che non ricordo, ma questo è un inizio. Penso che ci siano alcune altre cose che possiamo modificare, ma non sono sicuro al 100% di capire il codice ...
Giuseppe,

Ben fatto! Ho preso ispirazione. Confrontando il tuo codice ho anche trovato un mio bug che a volte portava a gruppi distrettuali molto piccoli (meno di 4 distretti). Ora è stato risolto.
NofP
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.