El gobierno tiene una oferta limitada de muros

28

Introducción

Conocidos códigos de golfistas nos prepararon para la inundación del fin del mundo . Las áreas en riesgo fueron evacuadas y la población se trasladó a terreno elevado.

Subestimamos la inundación (o tal vez hubo un error en el código de @ user12345). Algunas áreas de tierras altas se están acercando rápidamente al nivel del mar. Deben erigirse muros para garantizar la supervivencia de los campamentos ahora densamente poblados. Lamentablemente, el gobierno tiene un suministro limitado de muros.

Problema

Nuestro escenario del fin del mundo se describe con dos números en una sola línea, ny m. Después de esa línea hay nlíneas con mvalores por línea, separadas solo por un espacio único. Cada valor será uno de cuatro caracteres.

  • xInfranqueable. El agua no puede fluir aquí. Las paredes no se pueden erigir aquí.
  • -Inestable. El agua puede fluir a través de esto aquí. Las paredes no se pueden erigir aquí.
  • .Estable. El agua puede fluir por aquí. Las paredes se pueden erigir aquí.
  • oCampamento. El agua puede fluir por aquí. Si lo hace, todos mueren. Los muros no se pueden construir aquí.

El agua fluirá desde todos los bordes del mapa, a menos que el borde sea intransitable o se construya un muro en el azulejo. Escriba un programa que pueda generar la cantidad mínima de muros necesarios para proteger un campamento.

Entrada de ejemplo

 6 7
 x . . x x x x
 x . . x - - x
 x . x x - - x
 x . o o o - .
 x . o o o - .
 x x x x x x x

Salida de ejemplo

3

Supuestos

  • El agua solo fluye ortogonalmente
  • Los campamentos solo existen como un bloque contiguo ortonagonalmente por escenario
  • Siempre existirá una solución (aunque puede requerir grandes cantidades de paredes)
  • Los campamentos no se pueden ubicar en un borde, ya que el escenario no tendría solución
  • 2 n<<16
  • 2 m<<16
  • La entrada puede proporcionarse desde stdin, leerse desde "city.txt" o aceptarse como un argumento único

¡El código más corto gana!

Perno de lluvia
fuente
2
¿Sería aceptable que el programa sea correcto, pero que tarde más que el universo conocido para proporcionar una solución para ciertos casos del problema?
Claudiu
@Claudiu Soy algo nuevo en Code Golf. Mi requisito no pudo especificar un límite de tiempo, por lo que no existe uno. La carga recae en la respuesta para demostrar que una solución es correcta para todas las instancias del problema. Si tiene una solución que resuelve algunas (pero no todas) instancias de una manera inteligente / genial, todavía lo animo a publicarla solo por diversión.
Rainbolt
2
El código de golf generalmente no requiere restricciones de tiempo.
Hosch250
¡Guay! Otra P: ¿se requiere que la entrada sea como usted especificó o podemos ponerla en otra forma?
Claudiu
@Claudiu No puedo aceptar nada fuera de los requisitos. Sin embargo, puede sugerir una edición de los requisitos utilizando el botón Editar . Como todavía no hay respuestas, probablemente acepte la edición de inmediato.
Rainbolt

Respuestas:

10

Mathematica, 257253 caracteres

d="city.txt"~Import~"Table";g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

La entrada se lee desde "city.txt".

Explicación:

Mathematica tiene muchas funciones para tratar con gráficos.

Primero, leo los datos de "city.txt".

d="city.txt"~Import~"Table";

Luego construyo un gráfico de cuadrícula con 'm' * 'n' vértices ( GridGraph@d[[1,{2,1}]]), y agrego un "vértice en el infinito" que está conectado a cada vértice en los "bordes" del gráfico. Este vértice es de donde fluye el agua.

g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];

Y o, xy sdenota las posiciones de "o", "x" y "." respectivamente.

{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};

Luego, para cualquier subconjunto wde s(los subconjuntos están ordenados por longitud), elimino los vértices en xy wdesde g( VertexDelete[g,x⋃w]), y encuentro la longitud de la ruta más corta desde el "vértice en el infinito" hasta el campamento o. Si la longitud es infinita, entonces el campamento estará a salvo. Entonces, la longitud del primero wes el número mínimo de paredes requeridas para proteger un campamento.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]
alephalpha
fuente
¡Agradable! Pensé que me sacarían con un enfoque diferente en un idioma diferente.
Claudiu
1
Votar, pero lo haría con mayor orgullo si explicas tu código para el resto de nosotros.
Michael Stern
¿Puede alguien garantizar que esta respuesta es correcta o proporcionar un intérprete en línea para "Mathematica"? Tener problemas para encontrar uno.
Rainbolt
1
@Rusher Lo he verificado y es sólido. No hay un intérprete en línea para MM, pero hay un formato de documento CDF descargable con el que yo y un par de personas hemos comenzado a experimentar para compartir soluciones. También puede obtener Mathematica de forma gratuita con la computadora Raspberry Pi ARM, con la advertencia de que está limitado por la potencia informática de la caja. FWIW, nosotros, los usuarios de MM, hacemos todo lo posible para mantenernos honestos y estamos trabajando para que nuestras presentaciones sean más accesibles (un problema que también enfrentan los idiomas Matlab, Maple, MS que no funcionan en Mono, etc.)
Jonathan Van Matre
4

C, 827 799 522

Golfizado:

#define N for(
#define F(W,X,Y,Z) N i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}
p,m,z,w,h,o,i,u,l,x,y;char c[16][16];Q(){N u=0;u<h;u++)N l=0;l<w;l++)if(c[u][l]=='o'){x=u;y=l;S(x,>,m,--,i,y)S(y,>,m,--,x,i)S(y,<,w,++,x,i)S(x,<,h,++,i,y)}}main(int a, char **v){h=atoi(v[1]);w=atoi(v[2]);N m=-1;o<h;o++)N i=0;i<w;i++)scanf("%c",&c[o][i]);Q();printf("%d",z);}

La entrada se proporciona con la altura y con argumentos de línea de comando, y luego la cuadrícula se lee como una sola cadena en stdin de la siguiente manera: ./a.out 6 7 < inputdonde la entrada tiene esta forma (de izquierda a derecha, de arriba a abajo):

x..xxxxx..x - xx.xx - xx.ooo-.x.ooo-.xxxxxxx

"Legible":

#define F(W,X,Y,Z) for(i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}

/*Example of an expanded "S" macro:
p=1;
for(i=x;i>m;i--) if(c[i][y]==120) p=0;
if(p)
{
    for(i=x;i>m;i--)
    {
        if(c[i][y]==46)
        {
            c[i][y]='x';
            z++;
            Q();
            break;
        }
    }
}
else
{
    for(i= x;i > m;i --)
    {
        if(c[i][y]==120) break;
        else c[i][y]='o';
    }
}
*/

p,m,z,w,h,o,i,u,l,x,y;
char c[16][16];
Q(){
    for(u=0;u<h;u++)
        for(l=0;l<w;l++)
            if(c[u][l]=='o')
            {
        x=u;y=l;
        S(x,>,m,--,i,y)
        S(y,>,m,--,x,i)
        S(y,<,w,++,x,i)
        S(x,<,h,++,i,y)
            }
}

main(int a, char **v)
{
    h=atoi(v[1]);
    w=atoi(v[2]);
    for(m=-1;o<h;o++)
        for(i=0;i<w;i++)
            scanf("%c",&c[o][i]);
    P();
    Q();
    printf("%d\n",z);
    P();
}

//Omitted in golfed version, prints the map.
P()
{
    for(o=0;o<h;o++)
    {
        for (i=0;i<w;i++) printf("%c",c[o][i]);
        printf("\n");
    }   
}

No es tan corto como la solución de @Claudiu, pero funciona increíblemente rápido. En lugar de inundación desde los bordes, encuentra el campamento y trabaja hacia afuera desde las fichas 'o'.

  • Si encuentra un terreno inestable al lado del campamento, expande el campamento sobre él.
  • Si algún campamento en la cuadrícula no tiene al menos una pared en cada dirección, se mueve en esa dirección hasta que pueda construir una pared.
  • Después de colocar cada nueva sección de muro, vuelve a encontrar la siguiente sección de muro para colocar.

Ejemplos de ubicaciones de pared:

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx
Comintern
fuente
Oh enfoque interesante! ¿Siempre da la respuesta más corta? Por ejemplo, ¿qué respuesta da para este mapa ? Debe ser 3 (marcado donde van las paredes nuevas @). Traté de ejecutar tu código yo mismo, pero no pareció funcionar
Claudiu
Vaya, parece que el golf y el alcohol no se mezclan muy bien ... Jugué golf en un comportamiento indefinido. Debería arreglarse ahora junto con los 277 caracteres innecesarios.
Comintern
2
@Claudiu - Vea mi comentario arriba, los resultados para el mapa que publicó están en pastebin.com/r9fv7tC5 . Esto siempre debería dar la respuesta más corta, pero solo lo he probado con 10 o 15 mapas que pensé que podrían presentar casos de esquina. Sería curioso ver si alguien puede identificar mapas para los que falla.
Comintern
4

Python, 553 525 512 449 414 404 387 368 caracteres (+4? Para invocación)

Me divertí demasiado jugando al golf. ¡Es 82 bytes más grande si intentas comprimirlo! Ahora que es una medida de compacidad y falta de repetición.

R=range;import itertools as I
f=map(str.split,open('city.txt'))[1:]
S=[]
def D(q):
 q=set(q)
 def C(*a):
    r,c=a
    try:p=(f[r][c],'x')[a in q]
    except:p='x'
    q.add(a)
    if'.'==p:S[:0]=[a]
    return p<'/'and C(r+1,c)|C(r-1,c)|C(r,c+1)|C(r,c-1)or'o'==p
 if sum(C(j,0)|C(j,-1)|C(0,j)|C(-1,j)for j in R(16))<1:print n;B
D(S);Z=S[:]
for n in R(len(Z)):map(D,I.combinations(Z,n))

Los niveles de sangría son espacio, tabulación.

Uso :

Lee de city.txt:

6 7
x . . x x x x
x . . x - - x
x . x x - - x
x . o o o - .
x . o o o - .
x x x x x x x

Invoque de la siguiente manera:

$ python floodfill_golf.py 2>X
3

El 2>Xobjetivo es ocultar stderr ya que el programa se cierra al generar una excepción. Si esto se considera injusto, siéntase libre de agregar 4 caracteres para la invocación.

Explicacion :

Fuerza bruta simple. Chace un relleno de inundación y devuelve verdadero si golpea un campamento. Sin relleno adicional ya que tomó demasiado espacio para configurar el relleno correctamente. D, dado un conjunto de muros para rellenar, llama Cdesde todos los puntos del borde de manera tal que Ctenga en cuenta esos muros e imprime la longitud y las salidas si ninguno de ellos llega al campamento. La lista de paredes también se utiliza para realizar un seguimiento del relleno de inundación, por lo que no es necesario copiar el tablero. Trickily, Ctambién anexa ningún espacios vacíos que encuentra a una lista, S, por lo que la función Des también utilizado para primera construcción de la lista de espacios vacíos. Por esta razón, utilizo en sumlugar de any, para asegurarme de que todos los .correos electrónicos se recopilan en el primer recorrido.

Invoco Duna vez, luego copio la lista de espacios vacíos Zya que Sse seguirá agregando a (ineficiente, pero más barato en el recuento de caracteres). Luego uso itertools.combinationspara seleccionar cada combo de puntos vacíos, desde 0 puntos hacia arriba. Ejecuto cada combo a través deD e imprime la longitud del primero que funciona, lo que genera una excepción para salir del programa. Si no se encuentra ninguna respuesta, no se imprime nada.

Tenga en cuenta que actualmente, el programa no funciona si no se necesitan paredes. Sería +3 personajes para encargarse de este caso; No estoy seguro si es necesario.

También tenga en cuenta que este es un O(2^n)algoritmo, donde nes el número de puntos vacíos. Por lo tanto, para un tablero 15x15 completamente vacío con un campamento en el medio, esto tomará 2^(15*15-1)= 2.6959947e+67iteraciones para completar, ¡lo que va a ser mucho tiempo!

Claudiu
fuente
1

Groovy: 841 805 754

i=new File("city.txt").getText()
x=i[2] as int
y=i[0] as int
m=i[4..i.length()-1].replaceAll('\n','').toList()
print r(m,0)
def r(m,n){if(f(m))return n;c=2e9;g(m).each{p=r(it,n+1);if(p<c)c=p;};return c;}
def f(m){u=[];u.addAll(m);for(i in 0..(x*y)){for(l in 0..m.size()-1){n(l,u);s(l,u);e(l,u);w(l,u);}};m.count('o')==u.count('o')}
def n(i,m){q=i-x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def s(i,m){q=i+x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def e(i,m){q=i+1;if((((q%x!=0)&(m[q]=='!'))|(q%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def w(i,m){q=i-1;if((((i%x!=0)&(m[q]=='!'))|(i%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def g(m){v=[];m.eachWithIndex{t,i->if(t=='.'){n=[];n.addAll(m);n[i]='W';v<<n}};return v}

Sin golf:

def i = new File("city.txt").getText()
x=i[2].toInteger()
y=i[0].toInteger()
def m=i[4..i.length()-1].replaceAll('\n','').toList()
println r(m, 0)

def r(m, n){
    if(f(m)) return n
    def c = Integer.MAX_VALUE

    getAllMoves(m).each{ it -> 
        def r = r(it, n+1)
        if(r < c) c = r
    }
    return c;
}

def f(m){
    def t = []
    t.addAll(m)
    for(i in 0..(x*y)){
        for(l in 0..m.size()-1){
            n(l,t);s(l,t);e(l,t);w(l,t);
        }
    }
    m.count('o')==t.count('o')
}

def n(i,m){
    def t = i-x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def s(i,m){
    def t = i+x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def e(i,m){
    def t = i+1;
    if( ( ( (t%x!=0) && (m[t]=='!') ) || (t%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    } 
}

def w(i,m){
    def t = i-1;
    if( ( ( (i%x!=0) && (m[t]=='!') ) || (i%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def getAllMoves(m){
    def moves = []
    m.eachWithIndex { t, i ->
        if(t=='.'){
            def newList = []
            newList.addAll(m)
            newList[i]='W'
            moves << newList
        }
    }
    return moves
}

Mucho más golf por venir ...

Devuelve 2E9 si no hay solución.

md_rasler
fuente
0

Dyalog APL , 91 bytes

⊃∊{1∊a[⍸×{(×d)∧s 3∨/3∨⌿⍵}⍣≡4=d←0@⍵⊢a]:⍬⋄≢⍵}¨c[⍋≢¨c←(,⍳2⊣¨b)/¨⊂b←⍸2=a←(s←(4,4,⍨⍉)⍣2)'xo.'⍳⎕]

asume ⎕IO=0, usa características de v16.0 ( @y ), el tiempo de ejecución es exponencial en el número de .-s

se evalúa la entrada, debe ser una matriz de caracteres

'xo.'⍳ reemplace xcon 0, ocon 1, .con 2 y todos los demás con 3

s←(4,4,⍨⍉)⍣2 una función que rodea una matriz con 4s

a← asignar la matriz numérica rodeada de 4s a una variable a

b←⍸2= bes la lista de pares de coordenadas donde los 2 (es decir, los .-s) son

(,⍳2⊣¨b)/¨⊂b generar todas las combinaciones de elementos de b

c[⍋≢¨c←...] ordenarlos por tamaño

{... :⍬⋄≢⍵}¨ para cada combinación, marque algo y devuelva su longitud o una lista vacía

⊃∊ el primer resultado no vacío

d←0@⍵⊢a d es a con algunos elementos reemplazados por 0

4= crear matriz booleana: ¿dónde están los 4? es decir, el borde que agregamos

{...}⍣≡ siga aplicando la función {}hasta que el resultado se estabilice

3∨/3∨⌿⍵ "booleano o" cada elemento con sus vecinos

s el resultado será más pequeño, así que volvamos a crear el borde

(×d)∧ aplicar los elementos distintos de cero de d(los no muros) como una máscara booleana

a[⍸× ...] ¿Qué acorresponde a los 1 en nuestra matriz booleana?

1∊ ¿Hay algún 1, es decir o, campamentos?

ngn
fuente