Há água na minha janela

13

O cenário

Eu dirijo ao longo de uma estrada com meu carro e começa a chover. As gotas de chuva estão caindo na minha janela aleatoriamente e agora eu me pergunto: qual é a maior área molhada conectada?

A tarefa

Para facilitar, a janela é dividida em uma matriz de 10 * 10 quadrados. Seu trabalho é encontrar a maior área de gota d'água na janela.

Entrada

Existem duas entradas possíveis, você pode usar uma matriz bidimensional ou uma matriz unidimensional. Você pode escolher entre quaisquer entradas como stdin, etc ...
Exemplo:

// 2-dimensional:
[[0,1,0,0,0,0,1,0,0,0],
 [0,1,1,0,0,0,0,1,1,0],
 [0,1,1,0,0,0,0,1,0,0],
 [0,1,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,1,0],
 [0,0,0,1,1,0,0,0,1,0],
 [0,0,0,1,1,0,0,0,1,0],
 [0,0,0,0,0,1,1,0,1,0],
 [0,0,0,0,0,1,1,0,1,0],
 [0,0,0,0,0,0,0,0,0,0]]

// 1-dimensional
[0,1,0,0,0,0,1,0,0,0,
 0,1,1,0,0,0,0,1,1,0,
 0,1,1,0,0,0,0,1,0,0,
 0,1,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,1,0,
 0,0,0,1,1,0,0,0,1,0,
 0,0,0,1,1,0,0,0,1,0,
 0,0,0,0,0,1,1,0,1,0,
 0,0,0,0,0,1,1,0,1,0,
 0,0,0,0,0,0,0,0,0,0]

Resultado

Seu código deve especificar o tamanho da maior área conectada e as coordenadas xey das gotas d'água que pertencem a essa área no formato
"Tamanho: Coordenadas Z: (X1, Y1) (X2, Y2) .. "
Exemplo para a entrada anterior:

Size: 6 Coordinates: (1,0) (1,1) (2,1) (1,2) (2,2) (1,3)

A ordem das coordenadas não importa.

Regras

  • Gotas d'água são conectadas, se elas se tocam ortogonalmente
  • Conexões diagonais não contam
  • Pode haver muitas áreas e seu código precisa encontrar a maior
  • Um campo vazio é representado como "0" e um campo úmido como "1"
  • Poste sua solução com uma breve explicação e a saída da entrada anterior
  • O código mais curto nos próximos 7 dias vencerá
  • Se houver duas áreas com o mesmo tamanho, você pode escolher uma

Vencedor: Ventero com 171 - Ruby

Izlin
fonte
2
@Doorknob reclamando de um erro de digitação? OP é alemão.
Edc65
1
@ Doorknob eu mudei, obrigado. O prazo diz apenas quando determinarei o vencedor, mas você ainda poderá postar respostas.
Izlin
6
Eu diria que este é uma duplicata do codegolf.stackexchange.com/questions/32015/… .
187 Howard Howard
1
@TeunPronk: OP significa Pôster original. Pesquise no Google :)
justhalf
2
Alguns esclarecimentos sobre quais métodos de entrada são permitidos, exatamente, seriam ótimos.
Ventero

Respostas:

3

Ruby, 171 caracteres

r=eval *$*
u=(0..99).map(&v=->p{-~p*r[p]>0?" (#{r[p]=0;u=p%c=10},#{p/c})"+v[p+c]+v[p-c]+v[u>0?p-1:p]+v[u<9?p+1:p]:""}).max_by &:size
puts"Size: #{u.size/6} Coordinates:"+u

Entrada via parâmetro de linha de comando como matriz unidimensional.

Saída para a entrada de amostra: Size: 6 Coordinates: (1,0) (1,1) (1,2) (1,3) (2,2) (2,1)

Esta resposta usa uma abordagem simples de preenchimento, construindo uma lista de coordenadas para cada cluster de gota de chuva. A maior parte do código é realmente usada para verificação de limites e E / S.

Ventero
fonte
5

Python - 192

a=10;g+=[0]*a
def f(k):
 if g[k]:g[k]=0;return" (%d,%d)"%(k/a,k%a)+f(k+a)+f(k-a)+f(k+(k%a<9))+f(k-(k%a>0))
 return''
m=max(map(f,range(100)),key=len)
print"Size: "+`len(m)/6`+" Coordinates:"+m

Entrada (colar antes do código):

g=[0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0]

Obrigado Hobbies de Calvin pelas edições sugeridas!

Vetorizado
fonte
Você pode usar em map(f,range(100))vez de [f(i)for i in range(100)]salvar 8 caracteres. Também acredito que suas coordenadas são (y, x) não (x, y).
Hobbies de Calvin
3

C # - 548 523 522 511 503 476

(menos de 500 ... sim)

Tenho certeza de que há muito espaço para melhorias.

A maneira como inseri os dados foi inicializar uma matriz. Eu não incluí essa matriz na pontuação (se você acha que isso é trapaça, posso mudar o código, mas ele adicionará relativamente código porque o C # não é bom para analisar matrizes)

using o=System.Console;using l=System.Collections.Generic.List<int[]>;class P{
static int[,] a ={{0,1,0,0,0,0,1,0,0,0},{0,1,1,0,0,0,0,1,1,0},{0,1,1,0,0,0,0,1,0,0},{0,1,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,1,0},{0,0,0,1,1,0,0,0,1,0},{0,0,0,1,1,0,0,0,1,0},{0,0,0,0,0,1,1,0,1,0},{0,0,0,0,0,1,1,0,1,0},{0,0,0,0,0,0,0,0,0,0}};
static int w=10,h=w,x=0,y;static l t=new l(),m=new l();static void f(int r,int c){if(a[r,c]==1){a[r,c]=0;if(r<h)f(c,r+1);if(r>0)f(c,r-1);if(c<w)f(c+1,r);if(c>0)f(c-1,r);t.Add(new[]{c,r});}}static void Main(){for(;++x<w;)for(y=0;++y<h;){if(a[x,y]==1)f(x,y);if(t.Count>m.Count)m=t.FindAll(r=>true);t.Clear();}o.Write("Size: "+m.Count+" Coordinates: ");m.ForEach(c=>o.Write("({0},{1}) ",c[0],c[1]));}}

Teste-o em http://ideone.com/UCVCPM

Nota: A versão atual não funciona em ideone porque não gosta using l=System.Collections...; portanto, a versão em ideone está um pouco desatualizada (e mais longa)

Como funciona

Basicamente, verifica se existe um 1. Se encontrar um, ele usa o algoritmo de preenchimento Flood para substituir todos os adjacentes 1s' com 0e adiciona as coordenadas substituídos a uma lista temporária. Depois, compara a lista superior ( m) com a lista temporária ( t) e define mcomo tse tcontém mais elementos.

Christoph Böhmwalder
fonte
3

Mathematica - 180 bytes

Esta função utiliza uma matriz bidimensional.

Golfe

f@x_:=(c=MorphologicalComponents[x,CornerNeighbors->False];m=Last@SortBy[ComponentMeasurements[c,"Count"],Last];Print["Size: ",Last@m," Coordinates: ",Reverse/@Position[c,m[[1]]]])

Bonita

f@x_ := (
   c = MorphologicalComponents[x, CornerNeighbors -> False];
   m = Last@SortBy[ComponentMeasurements[c, "Count"], Last];
   Print["Size: ", Last@m, " Coordinates: ", Reverse/@Position[c, m[[1]]]]
   );

Exemplo

{0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0};
w=Partition[%,10];
f@w

Tamanho: 6 Coordenadas: {{1,2}, {2,2}, {2,3}, {3,2}, {3,3}, {4,2}}

A saída é um pouco anômala. O Mathematica começa a indexação em 1 em vez de 0 e usa {}para indicar a posição. Adicione 2 bytes ( -1) se as posições precisarem ser indexadas em 0. Adicione muitos bytes se eles precisarem usar em ()vez de {}:(

Explicação

fé uma função de x. Ele define ccomo uma transformação de x, onde cada (i, j) agora é igual a um número inteiro correspondente a qual componente conectado ele pertence. Envolve o trabalho principal:

MorphologicalComponents[w, CornerNeighbors -> False] // Colorize

insira a descrição da imagem aqui

Em seguida, mcalcula quantos elementos existem em cada componente, os classifica por esse número e obtém o último resultado (ou seja, com mais elementos). A última linha imprime a contagem e as posições dentro cdo índice contido em m.

mfvonh
fonte
2

Haskell, 246

r=[0..9]
q=[(i,j)|i<-r,j<-r]
t v p@(i,j)|elem p v||notElem p q||g!!j!!i==0=v|1<2=foldr(\(k,l)v->t v(i+k,j+l))(p:v)$zip[-1,0,1,0][0,-1,0,1]
(?)=map
a=t[]?q;(b,c)=maximum$zip(length?a)a
main=putStrLn.unwords$["Size:",show b,"Coordinates:"]++show?c

Entrada

Duas dimensões e cole antes do código como g, por exemplo:

g = [[0, 1, 1, ......, 0], [......], ....]

Ungolfed

field = [
 [0,1,0,0,0,0,1,0,0,0],
 [0,1,1,0,0,0,0,1,1,0],
 [0,1,1,0,0,0,0,1,0,0],
 [0,1,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,1,0],
 [0,0,0,1,1,0,0,0,1,0],
 [0,0,0,1,1,0,0,0,1,0],
 [0,0,0,0,0,1,1,0,1,0],
 [0,0,0,0,0,1,1,0,1,0],
 [0,0,0,0,0,0,0,0,0,0]
 ]
range = [0..9]
positions = [(i, j) | i <- range, j <- range]
directions = zip [-1, 0, 1, 0] [0, -1, 0, 1]
traverse visited pos@(i, j)
  | pos `elem` visited || pos `notElem` positions || field!!j!!i == 0 = visited
  | otherwise = foldr folder (pos:visited) directions
  where folder = (\(di, dj) visited -> traverse visited (i + di, j + dj))
blocks = map (traverse []) positions
(maxCount, maxBlock) = maximum $ zip (map length blocks) blocks
main = putStrLn.unwords $ ["Size:", show maxCount, "Coordinates:"] ++ map show maxBlock
Raio
fonte
2

Função C # 374byte

Esta é uma versão fortemente modificada da minha resposta para Você está na sala maior? . Ele pega uma matriz unidimensional de entradas e retorna uma sequência no estilo necessário. Ele funciona construindo conjuntos disjuntos a partir da entrada (primeiro loop), calculando o tamanho de cada conjunto e localizando o maior conjunto (segundo loop) e, em seguida, anexando quaisquer células desse conjunto a uma sequência de saída (terceiro loop) que é retornada .

static string F(int[]g){int s=10,e=0,d=s*s,a=0,b=d+1;int[]t=new int[b],r=new int[b];t[d]=d;System.Func<int,int>T=null,k=v=>t[T(v)]=t[v]<d?a:d;T=v=>t[v]!=v?T(t[v]):v;for(;a<d;a++)if(g[a]>0){e=t[a]=a;if(a>s)k(a-s);if(a%s>0)k(a-1);}else t[a]=d;for(;a-->0;)e=r[e]<++r[b=T(a)]&&b<d?b:e;var p="Size: "+r[e]+" Coordinates:";for(;d-->1;)p+=T(d)==e?" ("+d%s+","+d/s+")":"";return p;}

Menos golfe (e com código de teste):

class P
{
    static int[] z = {0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0};

    static string F(int[]g)
    {
        int s=10,e=0,d=s*s,a=0,b=d+1;

        int[]t=new int[b],r=new int[b];
        t[d]=d;
        System.Func<int,int>T=null,k=v=>t[T(v)]=t[v]<d?a:d;
        T=v=>t[v]!=v?T(t[v]):v;

        for(;a<d;a++)
            if(g[a]>0)
            {
                e=t[a]=a;
                if(a>s)k(a-s);
                if(a%s>0)k(a-1);
            }
            else
                t[a]=d;
        for(;a-->0;)
            e=r[e]<++r[b=T(a)]&&b<d?b:e;

        var p="Size: "+r[e]+" Coordinates:";
        for(;d-->1;)
            p+=T(d)==e?" ("+d%s+","+d/s+")":"";

        return p;
    }

    static void Main()
    {
        System.Console.WriteLine(F(z));
    }
}
VisualMelon
fonte
Isso me faz sentir mal com a minha solução de 476 bytes :( +1 para você, bom senhor.
Christoph Böhmwalder
1

JavaScript (EcmaScript 6) 183189

Uma função com entrada de matriz e valor de retorno de sequência. Se for necessária uma saída real (não está clara para mim), adicione 7 bytes para 'alert ()'.

W=(a,n=10,x=0)=>(F=p=>a[p]|0&&(a[p]=0,o+=' ('+p%n+','+(p/n|0)+')',1+F(p-n)+F(p+n)+F(p-(p%n>0))+F(p+((p+1)%n>0))),a.map((e,p)=>(t=F(p,o=''))>x&&(x=t,k=o)),'Size: '+x+' Coordinates:'+k)

Saída de teste

Size: 6 Coordinates: (1,0) (1,1) (1,2) (1,3) (2,2) (2,1)

Mais legível

W=(a,n=10,x=0)=>
(
  F=p=>
    a[p]|0&&(  
      a[p]=0,o+=' ('+p%n+','+(p/n|0)+')',
      1+F(p-n)+F(p+n)+F(p-(p%n>0))+F(p+((p+1)%n>0)) // modulo takes care of not overflowing out of a row
    ),
  a.map((e,p)=>(t=F(p,o=''))>x&&(x=t,k=o)), 
  'Size: '+x+' Coordinates:'+k
)

Explicação

Obtenha uma matriz de dimensão única e um parâmetro opcional com o tamanho de uma linha. A função também funciona com diferentes dimensões da matriz, mesmo x! = Y.

Pseudo-código:

 For each element, 
   try to fill. 
   During the fill operation build a string with the coordiinates. 
   Remember the longest fill and the corresponding string and 
 output that at the end.
edc65
fonte
1

JavaScript, 273

Função pega array e retorna string. Minha primeira tentativa foi de ~ 500 caracteres e não usou o Flood Fill. Este faz. Estou aprendendo JavaScript para que todas as sugestões sejam apreciadas.

Essa função percorre a matriz de entrada e, para cada 1 encontrado, começa lá e altera todos os conectados de 1s para 0 usando a função Preenchimento. Ao fazer isso, ele lembra o blob com mais 1s. A função Preenchimento altera a posição atual para 0 e, em seguida, chama-se na posição acima, à direita, abaixo e à esquerda.

function G(m){var B="",b=0;for(var p=0;p<m.length;p++)if(m[p]){var T="",t=0;
Z(p);if(t>b){b=t;B=T;}}return"Size: "+b+" Coordinates:"+B;function Z(p){if(m[p])
{m[p]=0;t++;T+=" ("+p%10+","+Math.floor(p/10)+")";if(p>9)Z(p-10);if(p%10)Z(p-
1);if(p<90)Z(p+10);if(p%10!=9)Z(p+1);}}}

Teste aqui: http://goo.gl/9Hz5OH

Código legível

var map = [0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
           ...
           0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

function F(map) {

    var bestBlob = "", bestLen=0;
    for (var p = 0; p < map.length; p++)
        if (map[p]) {
            var thisBlob = "", thisLen=0;
            Fill(p);
            if (thisLen > bestLen){
                bestLen=thisLen ; bestBlob = thisBlob;
            }
        }
    return "Size: " + bestLen + " Coordinates:" + bestBlob;

    function Fill(p) {
        if (map[p]) {
            map[p] = 0; thisLen++;
            thisBlob += " (" + p % 10 + "," + Math.floor(p / 10) + ")";
            if (p > 9) Fill(p - 10);
            if (p % 10) Fill(p - 1);
            if (p < 90) Fill(p + 10);
            if (p % 10 != 9) Fill(p + 1);
        }
    }
}
JeffSB
fonte
1

Scala, 420

Oi, minha entrada leva uma matriz 2D como a List[List[Int]], retorna umString

val o=for{(r, y)<-w.zipWithIndex;(v,x)<-r.zipWithIndex;if(v == 1)}yield(x,y);val a=o.flatMap(c=>o.collect{case(x,y)if{(x==c._1+1||x==c._1-1)&&y==c._2^(y==c._2+1||y==c._2-1)&&x==c._1}=>c->(x,y)}).groupBy(_._1).map(n => (n._1->n._2.map(t=>t._2)));val b=a.values.flatMap(v=>v.map(c=>a(c)++v));val l=b.collect{case x if (x.length==b.map(_.length).max)=>x}.head;println(s\"Size: ${l.length} Coordinates: ${l.mkString(" ")}\")

Explicação

Dada uma janela como a List[List[Int]], primeiro encontramos cada "1" e salvamos as coordenadas em uma lista. Em seguida, transformamos essa lista em uma Mapdas coordenadas de cada "1" para uma lista das coordenadas de cada "1" adjacente. Em seguida, use o mapa de adjacência para vincular transitivamente os sub-blobs em blobs e, finalmente, retornamos o maior blob (e ignoramos os blobs duplicados, pois a ordem das coordenadas retornadas não importa).

Mais legível

 val w = {
  List(//0,1,2,3,4,5,6,7,8,9
    List(0,1,0,0,0,0,1,0,0,0), //0
    List(0,1,1,0,0,0,0,1,1,0), //1
    List(0,1,1,0,0,0,0,1,0,0), //2
    List(0,1,0,0,0,0,0,0,0,0), //3
    List(0,0,0,0,0,0,0,0,1,0), //4
    List(0,0,0,1,1,0,0,0,1,0), //5
    List(0,0,0,1,1,0,0,0,1,0), //6
    List(0,0,0,0,0,1,1,0,1,0), //7
    List(0,0,0,0,0,1,1,0,1,0), //8
    List(0,0,0,0,0,0,0,0,0,0)) //9
}

case class Coord(x: Int, y: Int)

val ones: List[Coord] = for{
  (row, y)   <- w.zipWithIndex
  (value, x) <- row.zipWithIndex
  if (value == 1)        
} yield Coord(x,y)

val adjacencyMap: Map[Coord, List[Coord]] = ones.flatMap(keyCoord => ones.collect{
case Coord(adjacentX, adjacentY) if {
    (adjacentX == keyCoord.x + 1 || adjacentX == keyCoord.x - 1) && adjacentY == keyCoord.y ^ 
    (adjacentY == keyCoord.y + 1 || adjacentY == keyCoord.y - 1) && adjacentX == keyCoord.x
  }  => keyCoord->Coord(adjacentX,adjacentY)
}).groupBy(_._1).map(n => (n._1->n._2.map(t=>t._2) ))

val blobs: Iterable[List[Coord]] = adjacencyMap.values.flatMap(v => v.map(coord => adjacencyMap(coord)++v))

val largestBlob: List[Coord] = blobs.collect{case x if (x.length == blobs.map(b=> b.length).max) => x}.head

println(s"""Size: ${largestBlob.length} Coordinates: ${largestBlob.collect{case Coord(x,y) => (x,y)}.mkString(" ")}""")

A crítica é muito apreciada.

Julian Peeters
fonte