Trovare forme nell'array 2D, quindi ottimizzare


11

Mi è appena stata concessa un'immagine ... L'immagine in basso del mio gioco mostra alcuni blocchi oscurati, che sono stati riconosciuti come parte di una forma a "T". Come si può vedere, il codice ha oscurato i blocchi con le macchie rosse e non ha visto le forme a "T" con i contorni verdi.

Trovati i pattern desiderati, ma non ancora ottimizzati

Il mio codice scorre in sequenza x / y, contrassegna i blocchi come utilizzati, ruota la forma, si ripete, cambia colore, si ripete.

Ho iniziato a provare a risolvere questo controllo con grande trepidazione. L'idea attuale è di:

  • scorrere attraverso la griglia e prendere nota di tutte le occorrenze dei pattern (NON contrassegnare i blocchi come utilizzati) e inserirli in un array
  • scorrere nuovamente la griglia, questa volta notando quali blocchi sono occupati da quali schemi e quindi quali sono occupati da più schemi.
  • ripetendo ciclicamente la griglia, questa volta notando quali schemi ostruiscono quali schemi

Mi sento bene ... Cosa devo fare adesso?

Penso che dovrei

  • prova varie combinazioni di forme contrastanti, iniziando da quelle che ostruiscono prima la maggior parte degli altri schemi. Come posso avvicinarmi a questo?
  • usa il razionale che dice che ho 3 forme in conflitto che occupano 8 blocchi, e le forme sono 4 blocchi ciascuna, quindi posso avere solo un massimo di due forme.

(Intendo anche incorporare altre forme e probabilmente ci sarà la ponderazione del punteggio che dovrà essere presa in considerazione quando si attraversano le forme contrastanti, ma potrebbe essere un altro giorno)

Non penso che sia un problema di imballaggio del cestino, ma non sono sicuro di cosa cercare. Spero che abbia un senso, grazie per il tuo aiuto

EDIT Nonostante la chiarezza della domanda, tutti sembrano aver capito, sì,

Voglio trovare le forme "T" massime all'interno di ogni colore

(perché se ti dessi punti per due e tu ne avessi fatti tre, saresti un po 'seccato)


Un algoritmo avido potrebbe essere quello di dividere la scheda in raccolte di blocchi uniti. Quindi per ogni raccolta puoi provare a riempire con le forme e assegnare un punteggio al riempimento in base alla quantità di blocchi rimasti che non verrebbero oscurati. Un po 'mi fa pensare al problema en.wikipedia.org/wiki/Knapsack_problem .
Jonathan Connell,

2
Penso che manchi qualcosa nella domanda. Vuoi creare un algoritmo che trova il maggior numero possibile di gruppi a "T"?
Markus von Broady,

Se ti capisco allora stai andando nella direzione giusta. Non sei estremamente chiaro e mi piacerebbe se potessi elaborare.
AturSams,

Risposte:


3

Fammi vedere se ho capito bene, i blocchi contrassegnati in rosso, erano blu e l'algoritmo ha trovato una forma a T e li ha contrassegnati in rosso, è corretto? Il tuo obiettivo è quello di trovare il maggior numero possibile di forme a T con blocchi dello stesso colore, spero finora corretto. Attualmente li contrassegni una volta che li trovi e ciò diminuisce l'utilità dell'algoritmo (poiché potresti perdere la soluzione ottimale). Stai pensando di cercare tutte le forme e poi scegliere quali usare e quali non usare. Ho ragione finora? Causa si desidera massimizzare la quantità di blocchi contenuti all'interno delle forme a T al termine dell'algoritmo.

Se ho ragione, secondo me è la soluzione ottimale per la tua situazione.

Useremo la programmazione lineare intera.

Credo di averlo usato in passato:

http://sourceforge.net/projects/lpsolve/

http://lpsolve.sourceforge.net/5.5/Java/README.html

(Puoi farlo funzionare con molte lingue, l'ho usato con PHP, Java e C)

Ciò che faremo è registrare ogni possibile forma a T sulla scheda e quindi utilizzare ILP per massimizzare la quantità di blocchi coperti. ILP è esponenzialmente complesso. Considerando le dimensioni della tua tavola, questo non sarà un problema. Ho eseguito domande min / max molto più complicate sui grafici con ILP e ci sono voluti solo una frazione di secondo per completare e fino a 30-90 secondi con centinaia di vertici (nel tuo caso rientra nella frazione di secondo).

Cosa consiglierei di fare:

  1. Trova tutte le forme di linea possibili
  2. Trova tutte le intersezioni tra le forme delle linee dello stesso colore
  3. Trova tutte le possibili forme a T, cercando tutte le intersezioni.
  4. Definire una variabile booleana nel Problema lineare per ogni forma a T ( 0 <= Bi <= 1) Poiché i valori sono numeri interi, lascia 0 o 1.
  5. Crea le condizioni per ogni coppia di forme a T che si intersecano ( Bi + Bj <= 1)
  6. La funzione obiettivo sarà (somma dei blocchi in "T" Shape (i) * Bi)
  7. Esegui il solutore e scurisci le forme a T in cui i corrispondenti booleani del solutore sono 1 nella soluzione ottimale.

Questa è una conoscenza preziosa, ho usato solutori lineari spesso per progetti di lavoro.

L'ILP è fondamentalmente un modo per risolvere i problemi di selezione in cui si desidera ottenere un massimo o un minimo per alcune funzioni lineari.

Puoi leggere di più qui, utilizzando la Programmazione lineare integer e la programmazione lineare è la stessa per il programmatore solo che Integer è molto più complesso per il computer e ciò può comportare lunghi tempi di esecuzione. Non nel tuo caso, è molto semplice e nel peggiore dei casi dovrebbe impiegare meno di millisecondi.

Immagino che tu possa leggere di più qui:

http://en.wikipedia.org/wiki/Integer_linear_programming#Integer_unknowns

Questo lo spiega bene:

http://fisher.osu.edu/~croxton_4/tutorial/

Fondamentalmente è un risolutore di problemi di decisione, come prendere decisioni che massimizzano il risultato desiderato. Questo presuppone che la funzione che giudica il risultato sia lineare e che nel tuo caso specifico sia. La funzione che giudica il risultato in questo caso, riassume i blocchi per tutte le forme a T che hai deciso di scurire.

Matematicamente, come impostare le variabili: nel nostro caso attuale i booleani (ho oscurato la forma a T con l'indice i o no) ai valori ottimali per massimizzare il risultato che vogliamo: oscurare il maggior numero possibile di blocchi senza oscurare le forme a T intersecanti. Finché il risultato desiderato può essere calcolato con una funzione lineare quando tutte le variabili sono impostate, lo risolverà. Nel nostro caso, controlliamo quali forme a T abbiamo oscurato e sommiamo i blocchi che coprono.

inserisci qui la descrizione dell'immagine

So che questo non è banale, quindi se scegli di fare il salto, sentiti libero di commentare e lo elaborerò.


Grazie Arthur per il tuo aiuto. Potrebbero essere necessarie alcune letture per digerire. E sì, hai capito correttamente il problema. Sarei molto interessato se dovessi elaborare (no, no non è banale), ma questo dovrebbe aiutarmi ad arrivare dove sto andando!
Assemblatore

Quale lingua stai usando per l'implementazione?
AturSams,

ActionScript 3! il preferito di tutti!
Assembler

anch'io. Scriverò un'implementazione in as3 e la caricherò in un github per il download con commenti, lavorando passo dopo passo - Posso farlo più tardi oggi
AturSams

Hai aree specifiche 1-7 in cui vorresti che aggiungessi altri commenti o elaborassi? tra l'altro, una buona notizia per noi amanti dell'AS3, Adobe ha rilasciato FlasCC che supporta C ++ in modo da poter usare facilmente i solutori lineari esistenti. :)
AturSams,

4

Una volta che hai un elenco di tutte le forme a T (possibilmente sovrapposte) che si verificano nella tua griglia, ciò che ti rimane è un problema di imballaggio massimo impostato .

In generale, questo è un problema NP completo. Tuttavia, la griglia è abbastanza piccola (e in genere si suddivide in sottoproblemi indipendenti ancora più piccoli) che potrebbe essere fattibile ottenere soluzioni esatte.


Addendum: ecco un algoritmo di ricerca di backtracking di base che potrebbe fare il trucco:

function max_packing_recursive ( set A, set S, set M ):
    if |M| < |S| then let M = S;
    for each shape X in A do:
        remove X from A;
        let B = A;
        remove all shapes that intersect with X from B;
        if |M| < |B| + |S| + 1 then:        // upper bound
            let M = max_packing_recursive( B, S + {X}, M );
        end if
        if |M| >= |A| + |S| then return M;  // shortcut
    end for
    return M;
end function

function max_packing( set A ):
    return max_packing_recursive( A, {}, {} );
end function

Qui, {X, Y, Z}denota l'insieme contenente gli elementi X, Ye Z(con {}essendo l'insieme vuoto), e |Q|indica la dimensione del set Q.

Nella funzione ricorsiva, l'insieme Acontiene le forme disponibili per la soluzione rimanente, Scontiene le forme nell'attuale soluzione candidata ed Mè la soluzione massima fino ad ora (che potresti voler archiviare come variabile globale invece di restituirla al backup catena di chiamata). L'importante ottimizzazione si trova sulla linea contrassegnata con // upper bound, che elimina i rami dell'albero di ricerca che non possono probabilmente restituire una soluzione migliore di M.

(In realtà, poiché sappiamo che ogni forma a T contiene esattamente quattro siti, un limite superiore molto migliore potrebbe essere ottenuto sostituendo |B|con il numero di siti distinti coperti dalle forme in B, diviso per quattro e arrotondato per difetto (e allo stesso modo per |A|il linea contrassegnata con // shortcut). L'algoritmo come indicato sopra, tuttavia, funziona per raccolte arbitrarie di forme.)

Una possibile ulteriore ottimizzazione, che non ho implementato sopra, sarebbe quella di verificare all'inizio della funzione ricorsiva se si Adivide in più sottoinsiemi indipendenti, nel senso che nessuna forma in diversi sottoinsiemi si sovrappone e, in tal caso, applicare il algoritmo per ciascuno dei sottoinsiemi separatamente. (In ogni caso, ti consigliamo di farlo almeno una volta al livello più alto prima di chiamare l'algoritmo ricorsivo.) Ordinare le forme in modo Aappropriato prima di passarle sopra, ad esempio in ordine crescente in base al numero di forme sovrapposte, potrebbe anche aiutare .


Sì, penso che potrebbe usare un ILP per risolverlo relativamente indolore a causa delle dimensioni del problema. 2 ^ 20 ~ = 1.000.000 quindi, dato che possono esserci solo così tante forme a T, dovrebbe andare bene usando un risolutore lineare per questo . È chiaramente esponenzialmente complesso (almeno fino a quando qualcuno non riesce a dimostrare che p = np). Le dimensioni consentono di evitare l'euristica in questo caso relativamente semplice.
AturSams,

Ilmari, grazie mille. Anche questa risposta richiederà alcuni spunti per capire. Il bit di forme arbitrarie potrebbe essere utile nelle iterazioni future.
Assemblatore
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.