Faça um pouco de continente

11

Vamos imaginar que temos uma matriz de bits (que contém pelo menos um 1):

0 1 0 1 1 0 1 0 0 1 0
0 1 0 1 0 0 1 0 1 1 0
0 0 1 0 1 1 0 1 0 1 0
1 1 0 0 1 0 0 1 1 0 1
0 0 0 1 0 1 1 0 0 1 0

Queremos definir alguns dos bits nessa matriz, de forma que eles formem um blob contíguo de 1s, no qual todos 1sejam direta ou indiretamente conectados entre si 1por meio de movimento ortogonal:

0 1 1 1 1 1 1 0 0 1 0
0 1 0 1 0 0 1 0 1 1 0
0 1 1 0 1 1 1 1 0 1 0
1 1 0 0 1 0 0 1 1 1 1
0 0 0 1 1 1 1 0 0 1 0

(Você pode ver isso mais claramente pesquisando 1com o recurso "encontrar" do navegador).

No entanto, também queremos minimizar o número de bits que definimos.

A tarefa

Dada uma matriz (ou matriz de matrizes) de bits ou booleanos, retorne o número mínimo de bits que precisam ser configurados para criar um continente contíguo de 1s. Deveria ser possível passar de um bit definido na matriz para outro apenas viajando em uma direção ortogonal para outros bits definidos.

Isso é , então o menor envio válido (medido em bytes) vence.

Casos de teste

0 1 0 1 1 0 1 0 0 1 0
0 1 0 1 0 0 1 0 1 1 0
0 0 1 0 1 1 0 1 0 1 0
1 1 0 0 1 0 0 1 1 0 1
0 0 0 1 0 1 1 0 0 1 0
=> 6

1 0 0 0 0 0 1 0 0
1 1 0 0 1 1 1 0 0
1 1 1 0 1 1 1 1 1
0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1
0 1 0 0 0 0 1 1 0
1 0 0 0 0 0 1 0 0
=> 4

0 0 0 1 1 1 0 1 1
0 0 1 0 0 0 0 1 0
0 0 1 1 1 1 1 1 0
1 1 0 0 1 1 0 0 0
0 0 1 1 1 0 0 1 1
0 1 1 1 0 0 0 0 0
1 1 1 0 0 1 1 1 0
1 1 1 0 1 1 0 1 1
0 0 0 0 1 0 0 0 1
1 1 0 0 1 1 0 1 1
0 0 0 0 0 0 0 1 0
0 1 1 1 1 0 0 0 0
0 0 0 1 1 0 0 0 1
0 1 0 0 1 0 1 1 0
0 1 1 1 0 0 0 0 1
=> 8

1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
=> 0
Esolanging Fruit
fonte
1
Isso precisa de um pouco mais de explicação. O que é um "blob contíguo" em uma matriz?
NoOneIsHere
11
Como o problema é conhecido como NP-hard , não é um bom problema para o algoritmo mais rápido .
Peter Taylor
1
@ Peter Taylor e esolangingfruit NP-Hardness
FantaC
1
À luz dos comentários de Peter Taylor e HyperNeutrino e do fato de a pergunta não ter respostas no momento, estou mudando o método de pontuação para código-golfe .
Esolanging Fruit
1
O que devemos fazer se não houver 1na matriz?
Colera Su

Respostas:

1

C (gcc), 308 306 bytes

A função frecebe (height, width, flattened array, pointer to ans)e retorna a resposta pelo ponteiro.

Se não houver 1na matriz, ele retornará 0.

#define v A[i]
N,M,K,R,C,T,i,*A;s(x,y){i=x*M+y;if(!(x<0|y<0|x>=N|y>=M|v^1))v=2,s(x,y+1),s(x,y-1),s(x+1,y),s(x-1,y);}g(i){if(C<R){if(i^K){g(i+1);if(!v)C+=v=1,g(i+1),v=0,C--;}else{T=1;for(i=0;i<K&&!v;i++);s(i/M,i%M);for(i=0;i<K;i++)T&=v^1,v=!!v;if(T)R=C;}}}f(n,m,a,b)int*a,*b;{K=R=(N=n)*(M=m),A=a;g(0);*b=R;}

Experimente online!

Ungolfed:

N,M,R,C,T,i,*A; // height, width, result, recursion depth

s(x,y)
{ // depth first search: replace all 1 in the same connected component with 2
    i=x*M+y;
    if(!(x<0|y<0|x>=N|y>=M|A[i]^1)) { // check if out of boundary
        A[i]=2;
        s(x, y+1),s(x, y-1),s(x+1, y),s(x-1, y);
    }
}

g(i)
{ // enumerate all posible solutions
    if(C<R) {
        if(i!=N*M) {
            g(i+1);      // nothing change for this entry
            if (!A[i]) { // set the entry to 1
                C++, A[i]=1;
                g(i+1);
                C--, A[i]=0;
            }
        }
        else {
            T=1;
            for (i=0; i<N*M && !A[i]; i++); // find first non-zero entry
            s(i/M, i%M);     // replace the connected component
            for (i=0; i<N*M; i++) {
                T&=A[i]!=1;   // check if no other components
                A[i]=!!A[i]; // change 2s back to 1
            }
            if (T) R=C;      // update answer
        }
    }
}

f(n,m,a,b)int*a,*b;{
    R=(N=n)*(M=m), A=a;
    g(0);
    *b=R;
}
Colera Su
fonte
0

Python 2 , 611 bytes

Um programa completo que leva uma lista de listas através da entrada do usuário. As funções Ie dcontam o número de ilhas na matriz. O loop for no final enumera todas as possibilidades de onde você pode alterar 0s para 1s; se houver uma ilha, o número de 1s adicionado à lista será deixado C. O mínimo dessa lista é o número mínimo de inversões de bits necessárias para conectar quaisquer ilhas. É um algoritmo muito lento e, portanto, não executa os casos de teste dados abaixo dos 60 anos (não tentei mais), mas tentei alguns casos de teste menores (~ 5x5) e parece estar funcionando corretamente. Eu peguei o algoritmo de contagem de ilhas nesta página.

from itertools import*
def d(g,i,j,v):
 v[i][j],R,C=1,[-1,1,0,0],[0,0,-1,1]
 for k in range(4):
	if len(g)>i+R[k]>=0<=j+C[k]<len(g[0]):
	 if v[i+R[k]][j+C[k]]<1and g[i+R[k]][j+C[k]]:v=d(g,i+R[k],j+C[k],v)
 return v
def I(g):
 w=len(g[0])
 v,c=[w*[0]for r in g],0
 for i in range(len(g)*w):
	if v[i/w][i%w]<1and g[i/w][i%w]>0:v=d(g,i/w,i%w,v);c+=1
 return c           
g=input()
C=[]
for p in [list(t)for t in product([0,1],repeat=sum(r.count(0)for r in g))]:
 h,G,x=0,[r[:]for r in g],len(g[0])
 for i in range(x*len(G)):
	if G[i/x][i%x]<1:h+=p[0];G[i/x][i%x]=p[0];del p[0]
 if I(G)<2:
	C.append(h)
print min(C)

Experimente online!

Versão pré -olfizada antes de otimizar algumas coisas:

from itertools import*
def d(g,i,j,v):
    v[i][j]=1
    R=[-1,1,0,0]
    C=[0,0,-1,1]
    for k in range(4):
        if len(g)>i+R[k]>=0<=j+C[k]<len(g[0]):
            if v[i+R[k]][j+C[k]]<1:
                if g[i+R[k]][j+C[k]]:
                    v=d(g,i+R[k],j+C[k],v)
    return v
def I(g):
    w=len(g[0])
    v=[[0]*w for r in g]
    c=0
    for i in range(len(g)):
        for j in range(w):
            if v[i][j]<1and g[i][j]>0:
                v=d(g,i,j,v)
                c+=1
    return c           
g=input()
z=sum(r.count(0)for r in g)
f=[list(t)for t in product('01',repeat=z)]
C=[]
for p in f:
    h=0
    G=[r[:]for r in g]
    x=len(G[0])
    for i in range(x*len(G)):
        exec('h+=int(p[0]);G[i/x][i%x]=int(p[0]);del p[0]'*(G[i/x][i%x]<1))
    if I(G)<2:
        C.append(h)
print min(C)
dylnan
fonte