Salva le oche dall'estinzione


13

Le specie di oche conosciute come Alex A sono note per risiedere in griglie triangolari costituite da 64 cellule:

cellule
(Immagine tratta da questo problema di Project Euler non correlato .)

Etichetteremo ogni cella con i numeri 0a 63partire dalla riga superiore e quindi spostandoci da sinistra a destra su ogni riga sottostante. Quindi la cella in alto è 0e la cella in basso a destra è 63.

Ogni cella ha tre bordi. Possiamo etichettare ciascun bordo nella forma in a,bcui ae bsono i numeri delle celle che condividono quel bordo. Ad esempio, il bordo tra la cella 0e 2verrebbe chiamato 0,2o 2,0(non importa in quale ordine li metti).

Il sistema di etichettatura per i bordi sul bordo della griglia è diverso, poiché le celle sul bordo della griglia hanno un bordo che non condividono con altre celle. Se un bordo è solo una parte di una cella, useremo la lettera X. Per esempio, i tre confini di cella 0sono 0,2, 0,Xe 0,X.

Alcune celle contengono oche . Tuttavia, queste oche saranno uccise da volpi malvagie (che provengono da fuori i confini della griglia) se non le proteggi. E se tutte le oche muoiono, BrainSteel sarà triste. Pertanto scriveremo un programma che costruisce recinti attorno alle oche per proteggerli dalle volpi. Le oche dovrebbero esistere in un singolo poligono di recinti completamente chiuso. Il nostro budget di recinzione è piuttosto basso, quindi usa il minor numero possibile di recinzioni.

Descrizione dell'input

Un elenco di numeri, separati da virgola, da 0a 63, che rappresentano le celle che contengono oche. Esempio:

6,12

Descrizione dell'uscita

Un elenco di bordi che devono avere recinzioni costruite su di essi per proteggere con successo le oche. Questo dovrebbe essere il minor numero possibile di recinzioni. Esempio:

5,6 6,7 11,12 12,13 

"Le oche dovrebbero esistere in un poligono di recinzioni completamente chiuso." Tutte le oche devono vivere nello stesso poligono o possono esserci più poligoni (o 0)?
feersum

@feersum Tutte le oche dovrebbero vivere nello stesso poligono. Ho modificato la domanda per chiarire.
assenzio

@ Katya Il poligono può avere autointersezioni o sezioni di larghezza zero? Pensa come una forma a clessidra.
orlp,

@orlp Che cos'è una sezione di larghezza zero?
assenzio

2
@orlp Il poligono non deve contenere sezioni di larghezza zero.
assenzio

Risposte:


10

C #, 530 byte

Programma C # completo, accetta input come una riga singola da STDIN e invia una riga singola a STDOUT, con un "" finale.

Questo è piuttosto lungo ... e ha troppe ripetizioni x / y / z, ma non sono stato in grado di ridurlo a qualcosa di sensato finora, e avere un esame in 2 ore, potrebbe tornare a questo domani.

using Q=System.Console;class P{static void Main(){int q=9,w=0,e=9,r=0,t=9,u=0,i=0,x=0,y=0,z=0,p=0;System.Action V=()=>{z=(int)System.Math.Sqrt(i);p=(x=i-z*z)%2;x/=2;y=(++z*z--+~i)/2;},W=()=>{Q.Write(i+","+(x<0|y++<0|z>7?"X":""+(z*z+2*x+1-p))+" ");};foreach(var g in Q.ReadLine().Split(',')){i=int.Parse(g);V();q=q>x?x:q;w=w<x?x:w;e=e>y?y:e;r=r<y?y:r;t=t>z?z:t;u=u<z?z:u;}for(i=64;i-->0;){V();if(!(x<q|x>w|y<e|y>r|z<t|z>u))if(p>0){if(y==r)W();if(x++==w)W();x--;if(z--==t)W();}else{if(y--==e)W();if(x--==q)W();x++;if(z++==u)W();}}}}

Questo diagramma spiega la maggior parte di ciò che sta succedendo.

Griglia descritta come x / y / z / (p), che mostra la soluzione di esempio

Riconosci che, poiché non possiamo avere sezioni di larghezza 0, un "esagono" sarà sempre la forma più economica (e ha il vantaggio di dare alle oche il massimo dello spazio in cui muoversi).

Il programma funziona prima traducendo tutti gli indici delle celle di input in coordini x / y / z e trovando il min / max di ciascuno di x / y / z.

z = floor(root(i))
x = floor((i - z^2) / 2)
y = floor((z+1)^2 - i - 1) / 2)
p = (i - z^2) % 2

Successivamente, passa attraverso ogni indice di cella e verificando se si adatta al limite "esagono" che abbiamo descritto. In tal caso, controlla se si trova su uno dei bordi estremi dei limiti (ovvero x = xmin o y = ymax) e aggiunge i bordi corrispondenti, se lo è. Deve capire l'indice del bordo accanto. Per xe z, li incrementiamo / diminuiamo come preferiamo, quindi utilizziamo la seguente formula:

i = z^2 + 2*x + (1-p)

Si noti che la "parità" cambia sempre e che y non è coinvolto. Per y, non dobbiamo cambiare nulla, ma il codice è un po 'disordinato perché deve eseguire i limiti dei "triangoli" per verificare se la cella della porta accanto dovrebbe essere una "X" oppure no.

Soluzione di esempio (celle con oche appena dentro dai tre angoli):

Input
2,50,62

Output
62,63 61,X 59,X 57,X 55,X 53,X 51,X 50,49 48,X 36,X 35,X 25,X 24,X 16,X 15,X 9,X 8,X 4,X 3,X 2,0 1,X 

Codice Tidier con commenti:

using Q=System.Console;

class P
{
    static void Main()
    {
        int q=9,w=0,e=9,r=0,t=9,u=0, // min/max x/y/z/ (init min high, and max low)
        i=0, // index of cell we are looking at
        x=0,y=0,z=0,p=0; // x,y,z dimension

        System.Action V=()=>
            { // translates the index into x/y/z/p
                z=(int)System.Math.Sqrt(i);
                p=(x=i-z*z)%2; // 'parity'
                x/=2; // see p assignment
                y=(++z*z--+~i)/2; // ~i == -i - 1
            },
            W=()=>
            { // writes out the edge of i, and the cell described by x/z/inverse of p   (the inversion of p handles y +/-)
                Q.Write(i+","+ // write out the edge
                        (x<0|y++<0|z>7?"X":""+(z*z+2*x+1-p)) // either X (if we go out of 'trianlge' bounds), or we translate x/z/inverse of p into an index
                        +" "); // leaves a trailing space (as shown in example output)
            };

        foreach(var g in Q.ReadLine().Split(',')) // for each cell with geese
        {
            i=int.Parse(g); // grab index of cell
            V(); // compute x/y/z/p
            q=q>x?x:q; // sort out mins/maxes
            w=w<x?x:w;
            e=e>y?y:e;
            r=r<y?y:r;
            t=t>z?z:t;
            u=u<z?z:u;

            // code like the above suggests a solution with a couple of arrays would be better...
            // I've not had success with that yet, but maybe in a couple of days I will try again
        }

        for(i=64;i-->0;) // for each cell
        {
            V(); // compute x/y/z/p
            if(!(x<q|x>w|y<e|y>r|z<t|z>u)) // if we are inside the 'hex' bounds
                if(p>0)
                { // x max, y max, z min
                    // these checks check that we are on the extremes of the 'hex' bounds,
                    // and set up the appropriate vars for W calls to put the edges in
                    // must do y first, because W modifies it for us (saves 2 bytes in the next block)
                    if(y==r) // don't need the ++ (can't go out of 'trianlge' bounds)
                        W();
                    if(x++==w)
                        W();
                    x--;
                    if(z--==t)
                        W();
                    //z++; not used again
                }
                else
                { // x min, y min, z max
                    if(y--==e) // do need the -- (used for 'trianlge' bounds checking)
                        W();
                    // y is reset in W, as such
                    if(x--==q)
                        W();
                    x++;
                    if(z++==u)
                        W();
                    //z--; not used again
                }
        }
    }
}

È possibile salvare un byte con using System;.
LegionMammal978,

@ LegionMammal978 infatti ne guadagna due facendolo .. Lo usa solo per Q.Write e Q.ReadLine. quelli, oltre all'istruzione using che ha ora è using Q=System.Console;Q.Write();Q.ReadLine()(45 byte) contro il tuo suggerimento using System;Console.Write();Console.ReadLine()(47 byte).
Kade,

Inoltre, si può cadere da 10 byte non inutilmente l'inizializzazione i, x, y, z, e pa 0.
LegionMammal978

@ LegionMammal978 sei sicuro? L'ho provato e sta dando errori per l'utilizzo di un vairable non assegnato.
Kade,

@ Vioz- Quali variabili? Quali righe nella versione annotata?
LegionMammal978,
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.