O governo tem um suprimento limitado de paredes

28

Introdução

Jogadores experientes em código nos prepararam para o dilúvio do dia do juízo final . As áreas de risco foram evacuadas e a população mudou-se para terrenos altos.

Subestimamos a inundação (ou talvez tenha ocorrido um erro no código do @ user12345). Algumas áreas altas estão se aproximando rapidamente do nível do mar. Muros devem ser erguidos para garantir a sobrevivência dos acampamentos agora densamente povoados. Infelizmente, o governo tem um suprimento limitado de muros.

Problema

Nosso cenário do dia do juízo final é descrito por dois números em uma única linha, ne m. Após essa linha, há nlinhas com mvalores por linha, separados apenas por um único espaço. Cada valor será um dos quatro caracteres.

  • xIntransitável. A água não pode fluir aqui. Paredes não podem ser erguidas aqui.
  • -Instável. A água pode fluir através disso aqui. Paredes não podem ser erguidas aqui.
  • .Estável. A água pode fluir por aqui. Paredes podem ser erguidas aqui.
  • oAcampamento. A água pode fluir por aqui. Se isso acontecer, todo mundo morre. Paredes não podem ser construídas aqui.

A água fluirá de todas as bordas do mapa, a menos que a borda seja intransitável ou uma parede seja construída sobre o ladrilho. Escreva um programa que possa gerar o número mínimo de paredes necessárias para proteger um acampamento.

Exemplo de entrada

 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

Saída de exemplo

3

Suposições

  • A água flui apenas ortogonalmente
  • Acampamentos existem apenas como um bloco ortogonalmente contíguo por cenário
  • Uma solução sempre existirá (embora possa exigir grandes quantidades de paredes)
  • Acampamentos não podem ser localizados em uma borda, pois o cenário não teria solução
  • 2 n<<16
  • 2 m<<16
  • A entrada pode ser fornecida pelo stdin, lida em "city.txt" ou aceita como um único argumento

O menor código vence!

Rainbolt
fonte
2
Seria aceitável que o programa estivesse correto, mas levaria mais tempo do que o universo conhecido existia para fornecer uma solução para determinadas instâncias do problema?
Claudiu
@ Claudiu Sou um pouco novo no Code Golf. Meu requisito falhou ao especificar um limite de tempo, portanto, um não existe. O ônus recai sobre a resposta para provar que uma solução está correta para todas as instâncias do problema. Se você tem uma solução que resolve algumas (mas não todas) instâncias de uma maneira inteligente / interessante, eu ainda o encorajo a publicá-la apenas por diversão.
precisa saber é o seguinte
2
O código de golfe normalmente não exige restrições de tempo.
precisa saber é o seguinte
Legal! Outra pergunta: é necessário que a entrada seja como você especificou ou podemos colocá-la de outra forma?
Claudiu
@ Claudiu Não posso aceitar nada fora dos requisitos. No entanto, você pode sugerir uma edição dos requisitos usando o botão de edição . Como ainda não há respostas, provavelmente aceitarei a edição imediatamente.
precisa saber é o seguinte

Respostas:

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}]

A entrada é lida "city.txt".

Explicação:

O Mathematica tem muitas funções para lidar com gráficos.

Primeiro, eu li os dados de "city.txt".

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

Então eu construo um gráfico de grade com 'm' * 'n' vértices ( GridGraph@d[[1,{2,1}]]) e adiciono a ele um "vértice no infinito" que é conectado a todos os vértices nas "arestas" do gráfico. Este vértice é de onde a água flui.

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

E o, xe sdenotam as posições de "o", "x" e "" respectivamente.

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

Então, para qualquer subconjunto wde s(os subconjuntos são classificados por comprimento), excluo os vértices in xe wfrom g( VertexDelete[g,x⋃w]) e encontro o comprimento do caminho mais curto do "vértice no infinito" ao acampamento o. Se o comprimento for infinito, o acampamento estará seguro. Portanto, o comprimento do primeiro wé o número mínimo de paredes necessárias para proteger um acampamento.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]
alefalpha
fonte
Agradável! Imaginei que seria enganado por uma abordagem diferente em um idioma diferente.
Claudiu
1
Voto positivo, mas eu o faria com mais orgulho se você explicasse seu código para o resto de nós.
Michael Stern
Alguém pode garantir que esta resposta está correta ou fornecer um intérprete online para o "Mathematica"? Tendo problemas para encontrar um.
Rainbolt
1
@ Rusher Eu verifiquei, e é sólido. Não há intérprete on-line para o MM, mas existe um formato de documento CDF para download com o qual eu e alguns outros começamos a experimentar para compartilhar soluções. Você também pode obter o Mathematica gratuitamente com o computador Raspberry Pi ARM, com a ressalva de que você está limitado pelo poder de computação da caixa. FWIW, nós, usuários MM, fazemos o possível para nos mantermos honestos e estamos trabalhando para tornar nossos envios mais acessíveis (um problema também enfrentado pelos idiomas Matlab, Maple, MS que não funcionam em Mono etc.)
Jonathan Van Matre
4

C, 827 799 522

Golfe:

#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);}

A entrada é fornecida com a altura e com os argumentos da linha de comando e, em seguida, a grade é lida como uma única string no stdin da seguinte forma: ./a.out 6 7 < inputonde a entrada está neste formato (da esquerda para a direita, de cima para baixo):

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

"Legível":

#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");
    }   
}

Nem tão curto quanto a solução da @Claudiu, mas ele é incrivelmente rápido. Em vez de inundar as bordas, encontra o acampamento e trabalha a partir dos tokens 'o'.

  • Se encontrar um terreno instável ao lado do acampamento, ele o expande.
  • Se algum acampamento na grade não tiver pelo menos uma parede em cada direção, ele se moverá nessa direção até poder construir uma parede.
  • Depois que cada nova seção de parede é colocada, ela volta a encontrar a próxima seção de parede a ser colocada.

Exemplos de canais de parede:

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
fonte
Oh abordagem interessante! Sempre dá a resposta mais curta? por exemplo, que resposta dá para este mapa ? Deve ser 3 (marcado para onde vão as novas paredes @). Eu tentei executar o código de mim, mas ele não parecia trabalho
Claudiu
Opa, parece que golfe e álcool não se misturam muito bem ... Eu joguei em um comportamento indefinido. Deve ser corrigido agora, juntamente com os 277 caracteres desnecessários.
Comintern
2
@ Claudiu - Veja meu comentário acima, os resultados para o mapa que você postou estão em pastebin.com/r9fv7tC5 . Isso deve sempre dar a resposta mais curta, mas eu apenas o testei com 10 ou 15 mapas que achei que poderiam apresentar casos de canto. Eu ficaria curioso para ver se alguém pode identificar os mapas pelos quais ele falha.
Comintern
4

Python, 553 525 512 449 414 404 387 368 caracteres (+4? Para invocação)

Eu me diverti muito jogando golfe nisso. É 82 bytes maior se você tentar compactá-lo! Agora isso é uma medida de compacidade e falta de repetição.

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))

Os níveis de recuo são espaço, guia.

Uso :

Lê 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 da seguinte maneira:

$ python floodfill_golf.py 2>X
3

O 2>Xé ocultar o stderr desde a saída do programa, gerando uma exceção. Se isso for considerado injusto, adicione 4 caracteres para a invocação.

Explicação :

Força bruta simples. Cfaz uma inundação e retorna true se atingir um acampamento. Sem preenchimento extra, pois foi necessário muito espaço para configurá-lo corretamente. D, dado um conjunto de paredes a serem preenchidas, chama Cde todos os pontos da borda, de modo que sejam Cresponsáveis ​​por essas paredes, e imprime o comprimento e as saídas, se nenhuma delas chegar ao acampamento. A lista de paredes também é usada para acompanhar o preenchimento, para que não seja necessária cópia do painel! Complicado, Ctambém anexa todos os pontos vazios encontrados a uma lista S, portanto, a função tambémD é usada para construir primeiro a lista de pontos vazios. Por esse motivo, eu uso, em vez de , para garantir que todos os s sejam coletados na primeira execução.sumany.

Invoco Duma vez e, em seguida, copio a lista de lugares vazios, Zpois Sele continuará sendo anexado a (ineficiente, mas mais barato na contagem de caracteres). Então eu uso itertools.combinationspara selecionar cada combinação de pontos vazios, de 0 pontos acima. Eu corro cada combinação De ela imprime o comprimento da primeira que funciona, gerando uma exceção para sair do programa. Se nenhuma resposta for encontrada, nada será impresso.

Observe que, atualmente, o programa não funciona se nenhuma parede for necessária. Seriam +3 caracteres para cuidar deste caso; não tenho certeza se é necessário.

Observe também que este é um O(2^n)algoritmo, onde nestá o número de pontos vazios. Assim, para uma placa de 15x15 completamente vazio com um acampamento no meio, isso vai levar 2^(15*15-1)= 2.6959947e+67iterações para completar, que vai ser um tempo muito longo, de fato!

Claudiu
fonte
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}

Ungolfed:

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
}

Muito mais golfe por vir ...

Retorna 2E9 se não houver solução.

md_rasler
fonte
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.'⍳⎕]

assume ⎕IO=0, usa os recursos da v16.0 ( @e ), o tempo de execução é exponencial no número de .-s

é entrada avaliada, deve ser uma matriz de caracteres

'xo.'⍳ substitua xpor 0, opor 1, .por 2 e todos os outros por 3

s←(4,4,⍨⍉)⍣2 uma função que envolve uma matriz com 4s

a← atribuir a matriz numérica cercada por 4s a uma variável a

b←⍸2= bé a lista de pares de coordenadas em que os 2s (ie .-s) são

(,⍳2⊣¨b)/¨⊂b gerar todas as combinações de elementos de b

c[⍋≢¨c←...] ordená-los por tamanho

{... :⍬⋄≢⍵}¨ para cada combinação, verifique algo e retorne seu comprimento ou uma lista vazia

⊃∊ o primeiro resultado não vazio

d←0@⍵⊢a dé acom alguns elementos substituídos por 0

4= criar matriz booleana - onde estão os 4s? ou seja, a fronteira que adicionamos

{...}⍣≡ continue aplicando a função {}até o resultado estabilizar

3∨/3∨⌿⍵ "booleano" ou "cada elemento com seus vizinhos"

s o resultado será menor, então vamos recriar a borda

(×d)∧ aplicar os elementos diferentes de zero de d(as não paredes) como uma máscara booleana

a[⍸× ...] o que acorresponde aos 1s em nossa matriz booleana?

1∊ existem 1s, ou seja o, acampamentos?

ngn
fonte