Pianta alberi in un parco - Il più velocemente possibile!


20

Questa sfida è ispirata a questa app . I casi di test sono presi in prestito da quell'app.


Questa è una sfida con il , in cui l'obiettivo è risolvere i più grandi casi di test nel minor tempo possibile. Sono forniti alcuni casi di test più piccoli, in modo che le persone possano testare i loro algoritmi più velocemente.


Ti verrà data una griglia di input quadrata, di dimensioni n-by-n dove 9 <= n <= 12 . Questa griglia sarà divisa in n aree, dove le celle di ciascuna area hanno identificatori univoci (userò lettere minuscole da al nel testo qui, ma puoi scegliere quello che ti piace, ad esempio numeri interi 1-12 ) .

L'input potrebbe essere simile al seguente (formato di input opzionale):

aabbbbbcc
adddbbbcc
adeeecccc
adddefgcc
hhhdifggg
hdddifffg
hhhiifffg
hihiifffg
iiiiiiggg

Oppure, più facile da visualizzare:

inserisci qui la descrizione dell'immagine

Sfida:

Devi posizionare 2 * n alberi in questo parco, secondo le seguenti regole:

  • Ci devono essere esattamente 2 alberi per colonna e 2 alberi per fila
  • Tutte le aree devono avere esattamente 2 alberi.
  • Nessun albero può essere adiacente ad un altro albero, in verticale, in orizzontale o in diagonale

La soluzione al layout sopra è:

inserisci qui la descrizione dell'immagine

Nota: esiste una sola soluzione per ciascun puzzle

Regole aggiuntive:

  • I formati di input e output sono opzionali
    • L'output potrebbe ad esempio essere un elenco di indici, una griglia con 1/0 che indica se c'è un albero in quella posizione o una versione modificata dell'input in cui sono indicati gli alberi
  • Il tempo di esecuzione deve essere deterministico
  • Il programma deve terminare entro 1 minuto sul computer di @ isaacg
    • Specifiche: 4 CPU, CPU i5-4300U a 1,9 GHz, 7,5 G di RAM.
  • Nel caso in cui il tuo programma non sia in grado di risolvere i due casi di test più grandi in un minuto ciascuno, il tempo per il secondo più grande ( n = 11 ) sarà il tuo punteggio. Perderai contro una soluzione che risolve il caso più grande.

Casi test:

Potrei modificare questo elenco se gli invii sembrano essere personalizzati per adattarsi a questi casi di test.

12 per 12 :

--- Input ---
aaaaabccccdd
aaaaabccccdd
aaaaabbbbddd
eeeafffgbghh
eeaafffgbghh
eefffffggghh
eeefijffghhh
iieiijjjjkhh
iiiiijjjjkhk
lljjjjjjjkkk
llllllkkkkkk
llllllkkkkkk
--- Solution ---
aaaaabcccCdD
aaaaaBcCccdd
aAaaabbbbdDd
eeeaffFgBghh
eeAaFffgbghh
eefffffGgGhh
EeefijffghhH
iiEiIjjjjkhh
IiiiijjjjkHk
lljJjJjjjkkk
lLllllkkKkkk
lllLllKkkkkk

11 per 11 :

--- Input ---
aaaaaaabbcc
adddabbbbcc
edddbbbbbbc
eddddbbbbbb
effffggghhh
effffgghhii
eefffjjhhii
eeeejjjhhii
eeejjjjkiii
jjjjjjkkiii
jjjjjkkkiii
--- Solution ---
aaAaaaabbCc
adddAbBbbcc
eDddbbbbbbC
eddDdBbbbbb
effffggGhHh
eFfffGghhii
eefFfjjhHii
EeeejjjhhiI
eeEjjjjKiii
JjjjJjkkiii
jjjjjkKkIii

10-by-10

--- Input ---
aaaaabccdd
aeaabbbccd
aeaabfbgcd
eeeaafggcd
eeeaafghcd
eeeiifghcd
ieiiigghcd
iiijighhcd
jjjjighhcd
jjjggghhdd
--- Solution ---
aaAaabccdD
aeaaBbBccd
aEaabfbgcD
eeeaaFgGcd
eEeAafghcd
eeeiiFghCd
IeiIigghcd
iiijigHhCd
JjJjighhcd
jjjgGghHdd

9-by-9

--- Input ---
aabbbbbcc
adddbbbcc
adeeecccc
adddefgcc
hhhdifggg
hdddifffg
hhhiifffg
hihiifffg
iiiiiiggg
--- Solution ---
aAbBbbbcc
adddbbBcC
adEeEcccc
AdddefgCc
hhhDiFggg
hDddifffG
hhhiIfFfg
HiHiifffg
iiiiiIgGg
--- Input ---
aaabbbccc
aaaabbccc
aaaddbcce
ffddddcce
ffffddeee
fgffdheee
fggfhhhee
iggggheee
iiigggggg
--- Solution ---
aaAbBbccc
AaaabbcCc
aaaDdBcce
fFddddcCe
fffFdDeee
fGffdheeE
fggfHhHee
IggggheeE
iiIgggGgg

"I formati di input e output sono opzionali, ma dovrebbero essere gli stessi" Cosa significa? Non riesco a visualizzare un elenco di elenchi contenenti 1 e 0 per alberi e non alberi senza preoccuparmi di produrre le aree?
Fatalizza il

@Fatalize, modificato. Penso che produrre una lista di indici o una griglia con 1/0 come suggerisci sia una buona idea.
Stewie Griffin,

1
Informazioni (se calcolo correttamente): Esistono 3647375398569086976 configurazioni per mettere 24 alberi in una griglia 12 * 12 solo per soddisfare (1):, There shall be exactly 2 trees per column, and 2 trees per rowquindi una forza bruta è probabilmente impossibile.
user202729,

"Non dovrebbe essere un grosso problema" : personalmente penso che lo sia. La mia attuale implementazione risolve il primo caso di test in ~ 150 ms e il terzo in 5 secondi ma non riesce a risolvere l'ultimo (che è "solo" 11x11) in un ragionevole lasso di tempo. Probabilmente richiederebbe una potatura in avanti molto più aggressiva - e quindi una quantità significativa di codice aggiuntivo - da completare entro 1 minuto.
Arnauld,

1
@Arnauld, ho cambiato il massimo a 11 poiché questo è il più grande caso di test. Puoi pubblicare la tua soluzione (come invio valido e in competizione), ma non vincerà se qualcuno pubblica una soluzione che risolve tutti i casi di test, indipendentemente dalla lunghezza del codice. Giusto?
Stewie Griffin,

Risposte:


7

JavaScript (ES6), 271 byte

Accetta input come una matrice di matrici di caratteri. Restituisce una matrice di maschere di bit (numeri interi) che descrivono la posizione degli alberi su ciascuna riga, in cui il bit meno significativo è la posizione più a sinistra.

f=(a,p=0,r=[S=y=0],w=a.length)=>a.some((R,y)=>a.some((_,x)=>r[y]>>x&1&&(o[k=R[x]]=-~o[k])>2),o=[])?0:y<w?[...Array(1<<w)].some((_,n)=>(k=n^(x=n&-n))<=x*2|k&-k^k|n&(p|p/2|p*2)||r.some((A,i)=>r.some((B,j)=>A&B&n&&i<y&j<i))?0:(w=r[y],f(a,r[y++]=n,r),r[--y]=w,S))&&S:S=[...r]

Formattato e commentato

f = (                                           // given:
  a,                                            //   - a = input matrix
  p = 0,                                        //   - p = previous bitmask
  r = [                                         //   - r = array of tree bitmasks
        S = y = 0 ],                            //   - S = solution / y = current row
  w = a.length                                  //   - w = width of matrix
) =>                                            //
  a.some((R, y) => a.some((_, x) =>             // if there's at least one area with more
    r[y] >> x & 1 && (o[k = R[x]] = -~o[k]) > 2 // than two trees:
  ), o = []) ?                                  //
    0                                           //   abort right away
  :                                             // else:
    y < w ?                                     //   if we haven't reached the last row:
      [...Array(1 << w)].some((_, n) =>         //     for each possible bitmask n:
        (k = n ^ (x = n & -n)) <= x * 2 |       //       if the bitmask does not consist of
        k & - k ^ k |                           //       exactly two non-consecutive bits,
        n & (p | p / 2 | p * 2) ||              //       or is colliding with the previous
        r.some((A, i) => r.some((B, j) =>       //       bitmask, or generates more than two
          A & B & n && i < y & j < i            //       trees per column:
        )) ?                                    //
          0                                     //         yield 0
        :                                       //       else:
          (                                     //
            w = r[y],                           //         save the previous bitmask
            f(a, r[y++] = n, r),                //         recursive call with the new one
            r[--y] = w,                         //         restore the previous bitmask
            S                                   //         yield S
          )                                     //
      ) && S                                    //     end of some(): return false or S
    :                                           //   else:
      S = [...r]                                //     this is a solution: save a copy in S

Casi test

Questo frammento include una funzione aggiuntiva per visualizzare i risultati in un formato più leggibile. È troppo lento per risolvere l'ultimo caso di test.

Durata prevista: ~ 5 secondi.


Nota dell'OP: questa richiesta è stata presentata quando la sfida era una sfida di golf di codice. È quindi perfettamente valido, anche se non è ottimizzato per l'attuale criterio vincente!
Stewie Griffin,

Tempi: impiega più di un minuto su 11x11.
isaacg,

Siamo in un sottaceto, forse puoi aiutare. Riesci a pensare a un modo per generare istanze di puzzle più grandi non banali?
Isaacg,

7

C, tempo ufficiale: 5ms per 12x12

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>

#define valT char
#define posT int

#ifndef _OPENMP
#  warning Building without OpenMP support
#  define omp_get_max_threads() 1
#  define omp_get_num_threads() 1
#  define omp_get_thread_num() 0
#endif

#define MIN_THREADED_SIZE 11

static void complete(posT n, valT *workspace) {
    const posT s = n * 3 + 2;

    const valT *regions = workspace;
    valT *output = &workspace[n*2+1];

    for(posT y = 0; y < n; ++ y) {
        for(posT x = 0; x < n; ++ x) {
//          putchar(output[y*s+x] ? '*' : '-');
            putchar(regions[y*s+x] + (output[y*s+x] ? 'A' : 'a'));
        }
        putchar('\n');
    }

    _Exit(0);
}

static void solveB(const posT n, valT *workspace, valT *pops, const posT y) {
    const posT s = n * 3 + 2;

    const valT *regions = workspace;
    const valT *remaining = &workspace[n];
    valT *output = &workspace[n*2+1];

    for(posT r = 0; r < n; ++ r) {
        if(pops[r] + remaining[r] < 2) {
            return;
        }
    }

    for(posT t1 = 0; t1 < n - 2; ++ t1) {
        posT r1 = regions[t1];
        if(output[t1+1-s]) {
            t1 += 2;
            continue;
        }
        if(output[t1-s]) {
            ++ t1;
            continue;
        }
        if((pops[t1+n] | pops[r1]) & 2 || output[t1-1-s]) {
            continue;
        }
        output[t1] = 1;
        ++ pops[t1+n];
        ++ pops[r1];
        for(posT t2 = t1 + 2; t2 < n; ++ t2) {
            posT r2 = regions[t2];
            if(output[t2+1-s]) {
                t2 += 2;
                continue;
            }
            if(output[t2-s]) {
                ++ t2;
                continue;
            }
            if((pops[t2+n] | pops[r2]) & 2 || output[t2-1-s]) {
                continue;
            }
            output[t2] = 1;
            ++ pops[t2+n];
            ++ pops[r2];
            if(y == 0) {
                complete(n, &workspace[-s*(n-1)]);
            }
            solveB(n, &workspace[s], pops, y - 1);
            output[t2] = 0;
            -- pops[t2+n];
            -- pops[r2];
        }
        output[t1] = 0;
        -- pops[t1+n];
        -- pops[r1];
    }
}

static void solve(const posT n, valT *workspace) {
    const posT s = n * 3 + 2;

    valT *regions = workspace;
    valT *remaining = &workspace[n];
    valT *pops = &workspace[n*s];
//  memset(&remaining[n*s], 0, n * sizeof(valT));

    for(posT y = n; (y --) > 0;) {
        memcpy(&remaining[y*s], &remaining[(y+1)*s], n * sizeof(valT));
        for(posT x = 0; x < n; ++ x) {
            valT r = regions[y*s+x];
            valT *c = &remaining[y*s+r];
            valT *b = &pops[r*3];
            if(*c == 0) {
                *c = 1;
                b[0] = y - 1;
                b[1] = x - 1;
                b[2] = x + 1;
            } else if(x < b[1] || x > b[2] || y < b[0]) {
                *c = 2;
            } else {
                b[1] = b[1] > (x - 1) ? b[1] : (x - 1);
                b[2] = b[2] < (x + 1) ? b[2] : (x + 1);
            }
        }
//      memset(&output[y*s], 0, (n+1) * sizeof(valT));
    }
    memset(pops, 0, n * 2 * sizeof(valT));

    posT sz = (n + 1) * s + n * 3;
    if(n >= MIN_THREADED_SIZE) {
        for(posT i = 1; i < omp_get_max_threads(); ++ i) {
            memcpy(&workspace[i*sz], workspace, sz * sizeof(valT));
        }
    }

#pragma omp parallel for if (n >= MIN_THREADED_SIZE)
    for(posT t1 = 0; t1 < n - 2; ++ t1) {
        valT *workspace2 = &workspace[omp_get_thread_num()*sz];
        valT *regions = workspace2;
        valT *output = &workspace2[n*2+1];
        valT *pops = &workspace2[n*s];

        posT r1 = regions[t1];
        output[t1] = pops[t1+n] = pops[r1] = 1;
        for(posT t2 = t1 + 2; t2 < n; ++ t2) {
            posT r2 = regions[t2];
            output[t2] = pops[t2+n] = 1;
            ++ pops[r2];
            solveB(n, &regions[s], pops, n - 2);
            output[t2] = pops[t2+n] = 0;
            -- pops[r2];
        }
        output[t1] = pops[t1+n] = pops[r1] = 0;
    }
}

int main(int argc, const char *const *argv) {
    if(argc < 2) {
        fprintf(stderr, "Usage: %s 'grid-here'\n", argv[0]);
        return 1;
    }

    const char *input = argv[1];
    const posT n = strchr(input, '\n') - input;
    const posT s = n * 3 + 2;

    posT sz = (n + 1) * s + n * 3;
    posT threads = (n >= MIN_THREADED_SIZE) ? omp_get_max_threads() : 1;
    valT *workspace = (valT*) calloc(sz * threads, sizeof(valT));
    valT *regions = workspace;

    for(posT y = 0; y < n; ++ y) {
        for(posT x = 0; x < n; ++ x) {
            regions[y*s+x] = input[y*(n+1)+x] - 'a';
        }
    }

    solve(n, workspace);

    fprintf(stderr, "Failed to solve grid\n");
    return 1;
}

Compilato con GCC 7 usando i flag -O3e -fopenmp. Dovrebbe avere risultati simili su qualsiasi versione di GCC con OpenMP installato.

gcc-7 Trees.c -O3 -fopenmp -o Trees

Il formato di input e output è come indicato nella domanda.

Sulla mia macchina ci vogliono 0,009s 0,008s 0,005s per l'esempio 12x12 e 0,022s 0,020s 0,019s per eseguire tutti gli esempi. Sulla macchina di riferimento, isaacg riporta 5ms per l'esempio 12x12 utilizzando la versione originale (non thread) del codice.

Uso:

./Trees 'aaabbbccc
aaaabbccc
aaaddbcce
ffddddcce
ffffddeee
fgffdheee
fggfhhhee
iggggheee
iiigggggg'

Solo un semplice risolutore di forza bruta, che lavora su una riga alla volta. Funziona a una buona velocità riconoscendo precocemente le situazioni impossibili (ad esempio, non rimangono celle nella regione, ma meno di 2 alberi nella regione).

Il primo aggiornamento migliora gli accessi alla cache mettendo i dati correlati vicini nella memoria e rende i calcoli dei possibili alberi rimanenti nel segmento leggermente più intelligenti (ora spiega il fatto che gli alberi non possono essere adiacenti). Estrae anche il ciclo più esterno in modo che siano necessari meno casi speciali nella parte più calda dell'algoritmo.

Il secondo aggiornamento fa funzionare il ciclo più esterno in parallelo tra i processori disponibili (usando OpenMP), aumentando la velocità lineare. Questo è abilitato solo per n> = 11, poiché l'overhead dei thread di generazione supera i vantaggi per le griglie più piccole.


Tempismo ufficiale: 5ms per 12x12. Se qualcun altro si avvicina, avremo bisogno di casi di test più grandi.
isaacg,

Siamo in un sottaceto, forse puoi aiutare. Riesci a pensare a un modo per generare istanze di puzzle più grandi non banali?
Isaacg,

@isaacg Bene dall'esempio illustrato, sembra che le griglie originali siano state create posizionando prima gli alberi (in uno schema cavaliere con lievi modifiche in quell'esempio, ma immagino che qualsiasi schema con 2 alberi per riga e colonna funzionerebbe) quindi adattando le regioni attorno in modo che ogni regione contenga 2 alberi. Sembra che dovrebbe essere un metodo abbastanza semplice per un essere umano da seguire per griglie arbitrariamente grandi.
Dave,

In effetti, guardando di nuovo, non è un modello di cavaliere con lievi modifiche, ma un modello di avvolgimento in cui ogni albero è sfalsato (1,2) dal precedente. Una volta che hai un modello, puoi consentire a righe e colonne di creare soluzioni meno strutturate, purché non lasci alberi adiacenti.
Dave,

5

Java (OpenJDK 8) , timing ufficiale: 1.2s su 12x12

modifica: non è più il codice golf

import java.util.*;

// Callable method, takes an int[][] and modifies it
static void f(int[][] areas){
    List<List<BitSet>> areaBitSets = new ArrayList<>();
    List<List<BitSet>> areaTreeBitSets = new ArrayList<>();
    for(int i = 0; i < areas.length; i++){
        areaBitSets.add(new ArrayList<BitSet>());
        areaTreeBitSets.add(new ArrayList<BitSet>());
    }

    // Add a bitset to our list representing each possible square, grouped by area
    for(int i=0; i < areas.length; i++){
        for(int j=0; j < areas.length; j++){
            BitSet b = new BitSet();
            b.set(i*areas.length + j);
            areaBitSets.get(areas[i][j]).add(b);
        }
    }

    // Fold each set onto itself so each area bitset has two trees
    for(int i=0; i < areas.length; i++){
        for(int j=0; j<areaBitSets.get(i).size()-1; j++){
            for(int k=j+1; k <areaBitSets.get(i).size(); k++){
                if(canFoldTogether(areaBitSets.get(i).get(j),areaBitSets.get(i).get(k), areas.length)){
                    BitSet b = (BitSet)areaBitSets.get(i).get(j).clone();
                    b.or(areaBitSets.get(i).get(k));
                    areaTreeBitSets.get(i).add(b);
                }
            }
        }
    }

    // Starting with area 0 add each area one at a time doing Cartesian products
    Queue<BitSet> currentPossibilities = new LinkedList<>();
    Queue<BitSet> futurePossibilities = new LinkedList<>();
    currentPossibilities.addAll(areaTreeBitSets.get(0));

    for(int i=1; i < areaTreeBitSets.size(); i++){
        while(!currentPossibilities.isEmpty()){
            BitSet b= (BitSet)currentPossibilities.poll().clone();

            for(BitSet c: areaTreeBitSets.get(i)){
                if(canFoldTogether(b,c,areas.length)){
                    BitSet d=(BitSet)b.clone();
                    d.or(c);
                    futurePossibilities.add(d);
                }
            }
        }
        currentPossibilities.addAll(futurePossibilities);
        futurePossibilities.clear();
    }

    // Get final output and modify the array
    BitSet b = currentPossibilities.poll();
    for(int i=0; i<areas.length*areas.length; i++){
        areas[i/areas.length][i%areas.length] = b.get(i)?1:0;
    }
}

// Helper method which determines whether combining two bitsets
// will still produce a valid output
static boolean canFoldTogether(BitSet a, BitSet b, int size){

    // See if there are trees too close to each other
    int c=-1;
    while((c=a.nextSetBit(c+1))>=0){
        int d=-1;
        while((d=b.nextSetBit(d+1))>=0){
            int r1=c/size;
            int r2=d/size;
            int c1=c%size;
            int c2=d%size;

            int rDifference = r1>r2 ? r1-r2 : r2-r1;
            int cDifference = c1>c2 ? c1-c2 : c2-c1;
            if(rDifference<2 && cDifference<2)
                return false;
        }
    }

    // Check for row and column cardinality
    BitSet f,g;
    for(int i=0; i<size; i++){
        f = new BitSet();
        f.set(i*size,(i+1)*size);
        g=(BitSet)f.clone();
        f.and(a);
        g.and(b);
        f.or(g);
        if(f.cardinality()>2){
            return false;
        }


        f=new BitSet();
        for(int j = 0; j<size; j++){
            f.set(j*size+i);
        }
        g=(BitSet)f.clone();
        f.and(a);
        g.and(b);
        f.or(g);
        if(f.cardinality()>2){
            return false;
        }
    }

    return true;
}

Provalo online!

Il collegamento TIO è per il caso di test 12x12. TIO riporta 2.429s per il tempo di esecuzione.

Accetta una matrice di numeri interi come input e modifica la matrice in modo che contenga 1s per gli alberi e 0s per i non-alberi.

Questo funziona per tutti i test. La più grande testcase funziona sulla mia macchina in meno di un secondo, anche se ho una macchina abbastanza potente

Codice di prova per il 12x12, può modificare per gli altri

public static void main(String[] args){
    int[][] test = {{0,  0,  0,  0,  0,  1,  2,  2,  2,  2,  3,  3}, 
            {0,  0,  0,  0,  0,  1,  2,  2,  2,  2,  3,  3}, 
            {0,  0,  0,  0,  0,  1,  1,  1,  1,  3,  3,  3}, 
            {4,  4,  4,  0,  5,  5,  5,  6,  1,  6,  7,  7}, 
            {4,  4,  0,  0,  5,  5,  5,  6,  1,  6,  7,  7}, 
            {4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  7,  7}, 
            {4,  4,  4,  5,  8,  9,  5,  5,  6,  7,  7,  7}, 
            {8,  8,  4,  8,  8,  9,  9,  9,  9,  10,  7,  7}, 
            {8,  8,  8,  8,  8,  9,  9,  9,  9,  10,  7,  10}, 
            {11,  11,  9,  9,  9,  9,  9,  9,  9,  10,  10,  10}, 
            {11,  11,  11,  11,  11,  11,  10,  10,  10,  10,  10,  10}, 
            {11,  11,  11,  11,  11,  11,  10,  10,  10,  10,  10,  10}};

    long l = System.currentTimeMillis();
    f(test);
    System.out.println("12x12: " + (System.currentTimeMillis() - l) + "ms");

    for(int[] t : test){
        System.out.println(Arrays.toString(t));
    }

}

Produce questo sul mio computer:

12x12: 822ms
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]

Nota dell'OP: questa richiesta è stata presentata quando la sfida era una sfida di golf di codice. È quindi perfettamente valido, anche se non è (solo) ottimizzato per l'attuale criterio vincente!
Stewie Griffin,

@StewieGriffin grazie per il commento. Quando ne avrò la possibilità, lavorerò per pulirlo un po 'dato che non è più un codice golf e vedrò se riesco a ottimizzarlo per un po' di velocità
PunPun1000

Tempi ufficiali: 1,2 secondi su 12x12.
isaacg,

Siamo in un sottaceto, forse puoi aiutare. Riesci a pensare a un modo per generare istanze di puzzle più grandi non banali?
Isaacg,

4

Clingo , ≈ 7 ms per 12 × 12, 116 byte

{t(X,Y):c(X,Y,Z)}=2:-Z=1..n.
:-X=1..n,{t(X,1..n)}!=2.
:-Y=1..n,{t(1..n,Y)}!=2.
:-t(X,Y),t(X+1,Y;X+1,Y+1;X,Y+1;X-1,Y+1).

(Le nuove righe sono opzionali e non conteggiate.)

Corri con clingo plant.lp - -c n=<n>dov'è <n>la dimensione della griglia. Il formato di ingresso è un elenco di c(X,Y,Z).istruzioni per ciascuna cella ( X, Y) colorato Z, con 1 ≤ X, Y, Zn, separati da spazi bianchi opzionale. L'output include t(X,Y)per ogni albero in ( X,Y ).

Il tempo è piuttosto insignificante in quanto è fondamentalmente solo il tempo di avvio, quindi considera questo un voto per casi di test più grandi.

dimostrazione

$ clingo plant.lp -c n=12 - <<EOF
> c(1,1,1). c(2,1,1). c(3,1,1). c(4,1,1). c(5,1,1). c(6,1,2). c(7,1,3). c(8,1,3). c(9,1,3). c(10,1,3). c(11,1,4). c(12,1,4).
> c(1,2,1). c(2,2,1). c(3,2,1). c(4,2,1). c(5,2,1). c(6,2,2). c(7,2,3). c(8,2,3). c(9,2,3). c(10,2,3). c(11,2,4). c(12,2,4).
> c(1,3,1). c(2,3,1). c(3,3,1). c(4,3,1). c(5,3,1). c(6,3,2). c(7,3,2). c(8,3,2). c(9,3,2). c(10,3,4). c(11,3,4). c(12,3,4).
> c(1,4,5). c(2,4,5). c(3,4,5). c(4,4,1). c(5,4,6). c(6,4,6). c(7,4,6). c(8,4,7). c(9,4,2). c(10,4,7). c(11,4,8). c(12,4,8).
> c(1,5,5). c(2,5,5). c(3,5,1). c(4,5,1). c(5,5,6). c(6,5,6). c(7,5,6). c(8,5,7). c(9,5,2). c(10,5,7). c(11,5,8). c(12,5,8).
> c(1,6,5). c(2,6,5). c(3,6,6). c(4,6,6). c(5,6,6). c(6,6,6). c(7,6,6). c(8,6,7). c(9,6,7). c(10,6,7). c(11,6,8). c(12,6,8).
> c(1,7,5). c(2,7,5). c(3,7,5). c(4,7,6). c(5,7,9). c(6,7,10). c(7,7,6). c(8,7,6). c(9,7,7). c(10,7,8). c(11,7,8). c(12,7,8).
> c(1,8,9). c(2,8,9). c(3,8,5). c(4,8,9). c(5,8,9). c(6,8,10). c(7,8,10). c(8,8,10). c(9,8,10). c(10,8,11). c(11,8,8). c(12,8,8).
> c(1,9,9). c(2,9,9). c(3,9,9). c(4,9,9). c(5,9,9). c(6,9,10). c(7,9,10). c(8,9,10). c(9,9,10). c(10,9,11). c(11,9,8). c(12,9,11).
> c(1,10,12). c(2,10,12). c(3,10,10). c(4,10,10). c(5,10,10). c(6,10,10). c(7,10,10). c(8,10,10). c(9,10,10). c(10,10,11). c(11,10,11). c(12,10,11).
> c(1,11,12). c(2,11,12). c(3,11,12). c(4,11,12). c(5,11,12). c(6,11,12). c(7,11,11). c(8,11,11). c(9,11,11). c(10,11,11). c(11,11,11). c(12,11,11).
> c(1,12,12). c(2,12,12). c(3,12,12). c(4,12,12). c(5,12,12). c(6,12,12). c(7,12,11). c(8,12,11). c(9,12,11). c(10,12,11). c(11,12,11). c(12,12,11).
> EOF
clingo version 5.1.0
Reading from plant.lp ...
Solving...
Answer: 1
c(1,1,1) c(2,1,1) c(3,1,1) c(4,1,1) c(5,1,1) c(6,1,2) c(7,1,3) c(8,1,3) c(9,1,3) c(10,1,3) c(11,1,4) c(12,1,4) c(1,2,1) c(2,2,1) c(3,2,1) c(4,2,1) c(5,2,1) c(6,2,2) c(7,2,3) c(8,2,3) c(9,2,3) c(10,2,3) c(11,2,4) c(12,2,4) c(1,3,1) c(2,3,1) c(3,3,1) c(4,3,1) c(5,3,1) c(6,3,2) c(7,3,2) c(8,3,2) c(9,3,2) c(10,3,4) c(11,3,4) c(12,3,4) c(1,4,5) c(2,4,5) c(3,4,5) c(4,4,1) c(5,4,6) c(6,4,6) c(7,4,6) c(8,4,7) c(9,4,2) c(10,4,7) c(11,4,8) c(12,4,8) c(1,5,5) c(2,5,5) c(3,5,1) c(4,5,1) c(5,5,6) c(6,5,6) c(7,5,6) c(8,5,7) c(9,5,2) c(10,5,7) c(11,5,8) c(12,5,8) c(1,6,5) c(2,6,5) c(3,6,6) c(4,6,6) c(5,6,6) c(6,6,6) c(7,6,6) c(8,6,7) c(9,6,7) c(10,6,7) c(11,6,8) c(12,6,8) c(1,7,5) c(2,7,5) c(3,7,5) c(4,7,6) c(5,7,9) c(6,7,10) c(7,7,6) c(8,7,6) c(9,7,7) c(10,7,8) c(11,7,8) c(12,7,8) c(1,8,9) c(2,8,9) c(3,8,5) c(4,8,9) c(5,8,9) c(6,8,10) c(7,8,10) c(8,8,10) c(9,8,10) c(10,8,11) c(11,8,8) c(12,8,8) c(1,9,9) c(2,9,9) c(3,9,9) c(4,9,9) c(5,9,9) c(6,9,10) c(7,9,10) c(8,9,10) c(9,9,10) c(10,9,11) c(11,9,8) c(12,9,11) c(1,10,12) c(2,10,12) c(3,10,10) c(4,10,10) c(5,10,10) c(6,10,10) c(7,10,10) c(8,10,10) c(9,10,10) c(10,10,11) c(11,10,11) c(12,10,11) c(1,11,12) c(2,11,12) c(3,11,12) c(4,11,12) c(5,11,12) c(6,11,12) c(7,11,11) c(8,11,11) c(9,11,11) c(10,11,11) c(11,11,11) c(12,11,11) c(1,12,12) c(2,12,12) c(3,12,12) c(4,12,12) c(5,12,12) c(6,12,12) c(7,12,11) c(8,12,11) c(9,12,11) c(10,12,11) c(11,12,11) c(12,12,11) t(1,7) t(1,9) t(2,3) t(2,11) t(3,5) t(3,8) t(4,10) t(4,12) t(5,5) t(5,8) t(6,2) t(6,10) t(7,4) t(7,12) t(8,2) t(8,6) t(9,4) t(9,11) t(10,1) t(10,6) t(11,3) t(11,9) t(12,1) t(12,7)
SATISFIABLE

Models       : 1+
Calls        : 1
Time         : 0.009s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time     : 0.000s

Per semplificare la gestione del formato di input / output, ecco i programmi Python per la conversione da e verso il formato indicato nella sfida.

Ingresso

import sys
print(' '.join("c({},{},{}).".format(x + 1, y + 1, ord(cell) - ord('a') + 1) for y, row in enumerate(sys.stdin.read().splitlines()) for x, cell in enumerate(row)))

Produzione

import re
import sys
for line in sys.stdin:
    c = {(int(x), int(y)): int(z) for x, y, z in re.findall(r'\bc\((\d+),(\d+),(\d+)\)', line)}
    if c:
        t = {(int(x), int(y)) for x, y in re.findall(r'\bt\((\d+),(\d+)\)', line)}
        n, n = max(c)
        for y in range(1, n + 1):
            print(''.join(chr(ord('aA'[(x, y) in t]) + c[x, y] - 1) for x in range(1, n + 1)))
        print()

Sembra che avremo bisogno di un caso di prova più grande. A proposito, vinceresti la versione golf di questa domanda - basta che i 2s cambino in 1s.
Dave,

Il tempismo ufficiale è di 18 millisecondi su 12x12, mi scuso. 1 errore di battitura, questo è il problema con le abbreviazioni.
Isaacg,

Siamo in un sottaceto, forse puoi aiutare. Riesci a pensare a un modo per generare istanze di puzzle più grandi non banali?
Isaacg,
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.