2009-11-19 34 views
6

Sto cercando alcuni suggerimenti qui perché non so da dove iniziare la ricerca di questo.Ordinamento di una matrice 2D binaria?

Ho un matrice 2D con 0 o 1 in ciascuna cella, come ad esempio:

1 2 3 4 
A 0 1 1 0 
B 1 1 1 0 
C 0 1 0 0 
D 1 1 0 0 

e vorrei di risolvere in modo è come "triangolare superiore" possibile, in questo modo:

4 3 1 2 
B 0 1 1 1 
A 0 1 0 1 
D 0 0 1 1 
C 0 0 0 1 

Le righe e le colonne devono rimanere intatte, ovvero gli elementi non possono essere spostati singolarmente e possono essere scambiati solo "interi".

Capisco che ci sarà probabilmente casi patologici in cui una matrice ha diverse possibili risultati ordinati (ad esempio stessa forma, ma si differenziano per l'identità dei righe/colonne "originali".)

Così, qualcuno può suggerire dove potrei trovare alcuni punti di partenza per questo? Una libreria/algoritmo esistente sarebbe grandiosa, ma mi accontenterò di conoscere il nome del problema che sto cercando di risolvere!

Dubito che sia un problema di algebra lineare in quanto tale, e forse c'è un qualche tipo di tecnica di elaborazione dell'immagine applicabile.

Tutte le altre idee a parte, la mia ipotesi iniziale è solo per scrivere un semplice inserimento sorta sulle righe, poi le colonne e iterare che fino a stabilizzarsi (e la speranza che la rilevazione dei casi patologici non è troppo difficile.)

Maggiori dettagli: alcune ulteriori informazioni su ciò che sto cercando di fare possono aiutare a chiarire. Ogni riga rappresenta un concorrente, ogni colonna rappresenta una sfida. Ogni 1 o 0 rappresenta "successo" per il concorrente in una particolare sfida.

Ordinando la matrice in modo che tutti i 1 siano in alto a destra, spero di fornire una classifica della difficoltà intrinseca di ogni sfida e una classifica dei concorrenti (che terrà conto della difficoltà delle sfide che hanno riuscii a, non solo il numero di successi)

Nota sulla risposta accettata:. ho accettato Simulated Annealing come "la risposta" con l'avvertenza che questa domanda non ha una risposta giusta. Sembra un buon approccio, anche se in realtà non sono riuscito a trovare una funzione di punteggio che funzioni per il mio problema.

+1

domande: (1) Si noti che non c'è niente che puoi fare con una matrice di tutti 1: siete bene con che? (2) Una volta che non ci sono zeri sotto la diagonale, ti preoccupi di dove gli 1 sono sopra la diagonale? (3) Ridurre al minimo il numero di 1 s sotto la diagonale è un criterio abbastanza buono? Che ne dici di minimizzare il numero di righe che hanno (almeno) un 1 sotto la diagonale? – ShreevatsaR

+0

Risposta 1) Sì, tutti gli zeri o tutti non si verificano mai, e se lo facessero, sarebbero per definizione tutti considerati equivalenti, quindi ordinarli in qualche altra permutazione non sarebbe un problema. – Tom

+0

Risposta 2 + 3) Sì, voglio che gli 1 siano il più vicino possibile alla cima di ogni colonna, vale a dire il maggior numero possibile di 1 nell'angolo in alto a destra. Nota che ci possono essere 1 sotto la diagonale e 0 sopra di esso, non è strettamente una matrice triangolare. – Tom

risposta

6

Un algoritmo basato su simulated annealing può gestire questo genere di cose senza troppo problemi. Non eccezionale se si hanno matrici piccole che molto probabilmente hanno una soluzione fissa, ma grandiose se le matrici diventano più grandi e il problema diventa più difficile.

(tuttavia, fallisce anche il vostro desiderio che gli inserimenti può essere fatto in modo incrementale.)

Preliminari

  1. escogitare una funzione di prestazione che "punteggi" una matrice - matrici che sono più vicini a la tua eccellenza dovrebbe avere un punteggio migliore rispetto a quelli che sono meno triangolari.

  2. Definire una serie di operazioni consentite nella matrice. La tua descrizione era un po 'ambigua, ma se riesci a scambiare le righe, una operazione sarebbe SwapRows(a, b). Un altro potrebbe essere SwapCols(a, b).

Il ciclo di ricottura

Non darò un'esposizione completa, ma l'idea è semplice. Esegui trasformazioni casuali sulla matrice usando le tue operazioni. Si misura quanto "migliore" è la matrice dopo l'operazione (utilizzando la funzione di prestazioni prima e dopo l'operazione). Quindi decidi se commettere quella trasformazione. Si ripete questo processo molto.

Decidere se eseguire il commit della trasformazione è la parte divertente: è necessario decidere se eseguire tale operazione o meno. Verso la fine del processo di ricottura, accettate solo le trasformazioni che hanno migliorato il punteggio della matrice. Ma prima, in un momento più caotico, consenti alle trasformazioni che non migliorano il punteggio. All'inizio, l'algoritmo è "caldo" e tutto va bene. Alla fine, l'algoritmo si raffredda e sono consentite solo buone trasformazioni. Se la pelle fresca linearmente l'algoritmo, quindi la scelta se accettare una trasformazione è:

public bool ShouldAccept(double cost, double temperature, Random random) { 
    return Math.Exp(-cost/temperature) > random.NextDouble(); 
} 

Si consiglia di leggere le informazioni contenute in ottima Numerical Recipes per ulteriori informazioni su questo algoritmo.

Breve storia, dovresti imparare alcuni di questi algoritmi generali. Ciò consentirà di risolvere grandi classi di problemi difficili da risolvere in modo analitico.

algoritmo di punteggio

Questa è probabilmente la parte più difficile. Dovrai ideare un segnapunti che guida il processo di ricottura verso il tuo obiettivo. Il segnapunti dovrebbe essere una funzione continua che si traduce in numeri più grandi mentre la matrice si avvicina alla soluzione ideale.

Come si misura la "soluzione ideale" - triangleness? Ecco un segnaposto ingenuo e facile: per ogni punto, si sa se dovrebbe essere 1 o 0.Aggiungi +1 al punteggio se la matrice è corretta, -1 se è sbagliata. Ecco alcuni codice in modo che può essere esplicita (non testato! Si prega di consultare!)

int Score(Matrix m) { 
    var score = 0; 
    for (var r = 0; r < m.NumRows; r++) { 
     for (var c = 0; c < m.NumCols; c++) { 
      var val = m.At(r, c); 
      var shouldBe = (c >= r) ? 1 : 0; 
      if (val == shouldBe) { 
       score++; 
      } 
      else { 
       score--; 
      } 
     } 
    } 
    return score; 
} 

Con questo algoritmo di punteggio, un campo casuale di 1 e 0 darà un punteggio pari a 0. Un "opposto" triangolo darà la punteggio più negativo, e la soluzione corretta darà il punteggio più positivo. Diffondere due punteggi ti darà il costo.

Se questo indicatore non funziona per te, dovrai "sintonizzarlo" finché non produce le matrici che desideri.

Questo algoritmo si basa sulla premessa che la messa a punto di questo scorer è molto più semplice rispetto alla definizione dell'algoritmo ottimale per l'ordinamento della matrice.

+3

Sì, ma questi "algoritmi di uso generale" di solito assorbono anche soluzioni realmente ottimali - possono spesso impiegare molto tempo per convergere o rimanere bloccati nei minimi locali. Puoi * dimostrare * qualcosa sui risultati ottenuti dalla ricottura simulata per questo specifico problema? – ShreevatsaR

+0

Questo dovrebbe funzionare, anche se in modo non deterministico. (a differenza delle altre risposte finora ...) +1.Forse puoi suggerire di introdurre un "pizzico" di trucchetto analitico/euristico nel mix, ad esempio identificando le righe o le colonne che hanno solo zeri, e posizionale rispettivamente in basso/a sinistra e rendi questi inamovibili w/r ai permessi trasformazioni. – mjv

+0

Il punto di attacco (almeno dove sono bloccato) è la funzione punteggio. Dato che, la ricottura simulata potrebbe sicuramente funzionare, ma come fai a sapere come è "a triangolo" una matrice? E sì, le due operazioni consentite sono SwapRow (a, b) e SwapCol (a, b). – Tom

0

Ecco un punto di partenza:

Convertire ogni riga bit binari in un numero

ordinare i numeri in ordine decrescente.

Quindi riconvertire ogni riga in binario.

+0

Sì, funziona per le righe, ma anche le colonne devono essere ordinate. – Tom

+0

D'accordo con Tom. – kafuchau

0

algoritmo di base:

  1. determinare le somme riga e memorizzare valori. Determinare le somme della colonna e memorizzare i valori.
  2. Ordinare le somme delle righe in ordine crescente. Ordinare la colonna somme in ordine crescente.

Si spera che si debba avere una matrice il più vicino possibile a una regione triangolare in alto a destra.

+0

Questo tipo di operazioni, ma non "finire" l'ordinamento dell'esempio che ho dato: le somme di riga sono A: 2, B: 3, C: 1, D: 2, colonne sono 1: 2, 2: 4 , 3: 2, 4: 0, quindi è ambiguo quale riga di ordine A, D e cols 1,3 dovrebbero entrare. – Tom

+0

Se sto capendo il resto del problema ... Forse dopo aver fatto i primi due passi, puoi guardare la nuova matrice e testare righe e colonne con le stesse somme uguali per vedere quali sono più densamente impacchettati con 1 in alto a destra/in alto (quindi indice di riga inferiore e indice di colonna più alto). – kafuchau

1

Mi è venuto in mente il seguente algoritmo e sembra funzionare correttamente.

Fase 1: spostare le righe con più 1 s su e colonne con la maggior parte 1 s destra.

  1. Prima le righe. Ordina le righe contando i loro 1 s. Non ci interessa se 2 righe hanno lo stesso numero di 1 s.
  2. Ora le colonne. Ordina i cols per contando i loro 1 s. Non ci interessa se 2 col hanno lo stesso numero di 1 s.

Fase 2: ripetizione fase 1 ma con criteri aggiuntivi, in modo da soddisfare il Variante matrice triangolare.
Criterio di righe: se 2 righe hanno lo stesso numero di 1 s, si sposta fino riga che inizia con meno 0 s.

Criterio di colli: se 2 cols hanno lo stesso numero di 1 s, ci muoviamo destra il colle che ha meno 0 s in fondo.


Esempio:

Fase 1

1 2 3 4      1 2 3 4     4 1 3 2 
A 0 1 1 0     B 1 1 1 0     B 0 1 1 1 
B 1 1 1 0 - sort rows-> A 0 1 1 0 - sort cols-> A 0 0 1 1 
C 0 1 0 0     D 1 1 0 0     D 0 1 0 1 
D 1 1 0 0     C 0 1 0 0     C 0 0 0 1 

Fase 2

4 1 3 2      4 1 3 2 
B 0 1 1 1     B 0 1 1 1 
A 0 0 1 1 - sort rows-> D 0 1 0 1 - sort cols-> "completed" 
D 0 1 0 1     A 0 0 1 1 
C 0 0 0 1     C 0 0 0 1 

Edit: si scopre che il mio algoritmo non dà adeguate matrici triangolari sempre.
Ad esempio:

Fase 1

1 2 3 4     1 2 3 4     
A 1 0 0 0     B 0 1 1 1     
B 0 1 1 1 - sort rows-> C 0 0 1 1 - sort cols-> "completed" 
C 0 0 1 1     A 1 0 0 0     
D 0 0 0 1     D 0 0 0 1     

Fase 2

1 2 3 4     1 2 3 4     2 1 3 4 
B 0 1 1 1     B 0 1 1 1     B 1 0 1 1 
C 0 0 1 1 - sort rows-> C 0 0 1 1 - sort cols-> C 0 0 1 1 
A 1 0 0 0     A 1 0 0 0     A 0 1 0 0 
D 0 0 0 1     D 0 0 0 1     D 0 0 0 1 
          (no change) 

(*) Forse una fase 3 aumenterà le buoni risultati. In questa fase posizioniamo le righe che iniziano con meno 0 s nella parte superiore.

+0

Ecco un input in cui non funziona: considera '[1 0 0 0], [0 1 1 1], [0 0 1 1], [0 0 0 1]' (che è già in alto- triangolare). Usando il tuo algoritmo su di esso arriva a '[1 0 1 1], [0 0 1 1], [0 0 0 1], [0 1 0 0]', che non lo è. (E se non si dà la forma iniziale e si inizia con quest'ultima matrice, allora l'algoritmo non cambia nulla: non trova la forma triangolare superiore.) – ShreevatsaR

+0

Oppure un semplice esempio 3x3: '[1 0 0], [0 1 1], [0 0 1] '. – ShreevatsaR

+0

@ShreevatsaR, hai ragione, grazie. Non produce sempre una matrice triangolare. Tuttavia, non fornisce le matrici che hai detto. Forse non hai applicato correttamente i passaggi. Controlla la mia modifica. Per quanto riguarda '[1 0 0], [0 1 1], [0 0 1]' darà '[1 0 1], [0 1 0], [0 0 1]'. –

0

righe trattano come numeri binari, con la colonna più a sinistra come il bit più significativo, e ordinarli in ordine, all'inizio decrescente verso il basso

Trattare le colonne come numeri binari con la riga in basso come il bit più significativo e ordinali in ordine crescente, da sinistra a destra.

Ripetere fino a raggiungere un punto fisso. Prova che l'algoritmo termina a sinistra come esercizio per il lettore.

0

Cerca un articolo del 1987 di Anna Lubiw su "Ordinazioni lessicali di matrici".

C'è una citazione qui sotto. L'ordine non è identico a quello che stai cercando, ma è piuttosto vicino. Se non altro, dovresti essere in grado di ottenere una buona idea da lì.

http://dl.acm.org/citation.cfm?id=33385

+1

Si prega di citare anche le informazioni nella tua domanda. Se il collegamento ACM cambia (accade di volta in volta, sono anche un membro), la tua risposta perde tutto il contesto. –

Problemi correlati