Merangkai Kalung Mutiara

18

Gambaran

Mutiara (atau Masyu) adalah permainan logika yang dimainkan di atas kisi-kisi. Ada mutiara hitam dan putih yang diletakkan di grid. Tujuannya adalah untuk membentuk satu loop tertutup yang berjalan melalui setiap mutiara hanya menggunakan segmen garis lurus dan sudut kanan.

Ada beberapa aturan yang mengatur bagaimana loop berinteraksi dengan mutiara:

  • Mutiara putih harus dilalui langsung , tetapi loop harus berputar di sel sebelumnya dan / atau berikutnya di jalurnya.
  • Mutiara hitam harus dihidupkan , tetapi loop harus berjalan lurus melalui sel berikutnya dan sebelumnya di jalurnya.
  • Lingkaran tidak boleh melewati atau memotong sendiri. Semua sel memiliki persis nol atau dua loop masuk / keluar.

Contoh teka-teki dari Wikipedia (dan solusinya):

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Tujuan Anda adalah untuk memecahkan teka-teki yang diberikan. Jika ada beberapa solusi yang mungkin, tidak masalah yang mana yang Anda berikan.

Memasukkan

Input akan berupa kotak persegi yang tidak terpecahkan . Contoh yang ditunjukkan di atas akan terlihat seperti ini:

..w.w.....
....w...b.
..b.b.w...
...w..w...
b....w...w
..w....w..
..b...w...
w...b....w
......ww..
..b......b

wadalah mutiara putih, badalah mutiara hitam, dan .merupakan sel kosong.

Asumsikan input valid. Ini berarti itu terbentuk dengan baik, dan setidaknya satu solusi mungkin. Semua puzzle yang valid setidaknya 3x3, dan mengandung setidaknya satu mutiara.

Keluaran

Output adalah serangkaian koordinat yang mewakili path. Sudut kiri atas grid adalah 0 0, kanan atas adalah n-1 0, di mana n adalah lebar grid.

Path hanyalah serangkaian koordinat yang diurutkan:

x1 y1 x2 y2 x3 y3 ...

Jalur diasumsikan ditutup, jadi Anda tidak perlu mengulang koordinat pertama di akhir, tetapi tidak ada penalti untuk melakukannya.

Output harus terdiri dari setidaknya semua sudut di jalan. Anda tidak harus mengeluarkan setiap sel di jalur jika tidak ada belokan. Misalnya, output untuk contoh dapat dimulai dengan:

1 0 5 0 5 1 ...

atau

1 0 2 0 3 0 4 0 5 0 5 1 ...

Keluaran seharusnya tidak mengandung sel yang tidak ada di jalur. Anda bisa mulai dari sel mana saja di jalur.


Potongan

Berikut cuplikan yang dapat Anda gunakan untuk memvisualisasikan solusi Anda. Cukup tempelkan di kisi yang sedang Anda kerjakan dan jalur yang Anda hasilkan. Saya sadar bahwa melihat kode saya itu menyakitkan, jadi saya sarankan Anda tidak;)


Uji Kasus

Kasing uji ini menunjukkan satu kemungkinan keluaran untuk setiap input (kecuali yang terakhir, yang ditunjukkan belum terpecahkan). Mungkin ada jalur lain yang valid, Anda mungkin pergi CW atau CCW atau mulai pada titik yang berbeda, dll. Solusi harus dapat menyelesaikan kasus uji dalam detik / menit / jam, bukan hari / minggu / ribuan tahun.

mutiara-3

...
w..
..b

0 0 1 0 2 0 2 1 2 2 1 2 0 2 0 1

mutiara-6

.wb..b
......
..b...
w.ww..
......
b....b

0 0 2 0 2 2 4 2 4 1 3 1 3 0 5 0 5 5 3 5 3 4 4 4 4 3 1 3 1 4 2 4 2 5 0 5 0 2 1 2 1 1 0 1

pearl-12

.....w.b.w..
ww..b...b...
.w.....b....
...wbww..b.b
....b.......
w.w.........
..w......b.b
.....bb.....
.....b.....w
w.ww..b.....
...w......w.
b..w.....b..
Geobit
sumber
Anda tidak memberikan solusi untuk test case terakhir ...
mbomb007
2
@ mbomb007 Benar.
Geobits
Jadi tidak ada solusi?
mbomb007
2
Ada solusinya. Saya membiarkannya terbuka sehingga jawaban akan menunjukkan sesuatu untuk usaha mereka. Juga, mungkin membantu memecahkan satu atau dua teka-teki dengan tangan untuk memahami aturan, dan itu sulit dilakukan jika semua contoh sudah dipecahkan.
Geobits
Apakah kisi 2x2 atau kisi yang lebih besar tanpa Mutiara dianggap sah (kalimat kedua menunjukkan tidak, dan poin tentang input tidak terpecahkan (jika tidak ada mutiara yang tidak tegang, harus dipecahkan))? Jika demikian, apakah Anda mengharapkan satu lingkaran, hanya tanpa mutiara di dalamnya, atau apa tepatnya? Agaknya tidak ada persyaratan untuk warna tertentu untuk hadir?
VisualMelon

Jawaban:

7

C, 590 640 760 880 963 1018

Brute force cukup cepat untuk ini. Tes 12x12 berjalan di bawah 10 ms. Mengetahui hal itu bisa memilih bahasa yang lebih tepat untuk bermain golf.

Saya tidak menganggap papan itu persegi karena teka-teki yang lebih besar cenderung tidak persegi.

Itu W mendefinisikan menetapkan batas pada dimensi papan. Batas aktual lebih kecil W - 2karena saya menggunakan baris tambahan untuk batas untuk menghindari pemeriksaan batas.

#define W 40
int Y,X,T,P,Q[W*W],D[]={-W,-1,1,W};char B[W*W],K[W*W],I[W];
t(x,d,s){for(P=0;B[x];x*=x!=*Q)s-=K[Q[P++]=x]-1,
d=(54202126527627840ll>>2*(d*7+B[x+=D[d]]%8))&3;return x?0:s;}
m(x){int c=K[x],u=B[x-W],U=u&7,l=B[x-1],L=l&7,r=0,
i=U!=3&U!=4&L!=2&L!=4,o=(39>>U)&1?57:70;o&=(52>>L)&1?42:85;
if(x/W>Y+1){for(;P--;)printf("%d %d ",Q[P]%W-1,Q[P]/W-1);exit(0);}
if(u>7)o&=U>4?~64:~6;if(l>7)o&=L>4?~32:~10;
for(o&=c?c>1?c>2?(r=8*i,96):(r=8,i*30):~0:1;o;r++,o/=2)
if(o&1)if(B[x]=r,r%8!=1||!t(x,0,T))m(x+1);B[x]=0;}
main(){for(;gets(I);Y++)for(X=0;I[X];X++)
T+=(K[X+1+Y*W+W]=I[X]/36)-1;m(W);}

Ujilah aku .

Ini adalah ujian yang lebih menantang:

.b.....b.b.......b..
.....w.....b.w....w.
....w.........w.....
..bb.....w.w.b....b.
.w.....b..b......w..
.....b..............
.b..........b.b..bw.
....w....w....b...w.
.......bb...b...w...
..b.......w.........
....b.w.....w.b...b.
w...b...w..b.w.w....
b.w....w............
...b.w......b..b...b
w......w.b.ww.......
.b....b..........b..
....b....w.bb.w...w.
w..b......w...b.....
b.....w.........w...
...b....w..w..b...w.
...................b
.b..w..bb.b..b..w...
........w......b....
b....w......b..b.b..
...b..bb.w.w........
...b.......w......w.
w...w.b.w.....b....b
............w..ww...
..b.b..b....b.......
....b.........w...b.
.ww.......b.w.w.....
b.....w..w.w...b....
....ww..b.b.w....w.w
.............bb..w..
.b....w.b.b........w
....bw..........b...

Saya beruntung kode saya menemukan solusinya cukup awal dalam menjalankan (<5 menit), tetapi pencarian lengkap membutuhkan waktu lebih lama (67 menit).

20x36

nutki
sumber
s / Brute force cukup cepat / C cukup cepat /
kirbyfan64sos
9

Python - 1669

Masih cukup panjang, tetapi cukup cepat untuk menjalankan contoh terakhir di bawah satu detik di komputer saya. Mungkin memungkinkan untuk membuat lebih pendek dengan biaya kecepatan, tetapi untuk saat ini cukup banyak setara dengan kode yang tidak diserobot.

Contoh output untuk test case terakhir:

0 11 1 11 2 11 3 11 4 11 4 10 3 10 2 10 1 10 1 9 2 9 3 9 4 9 4 8 3 8 3 7 4 7 5 7 5 6 5 5 6 5 6 6 6 7 7 7 8 7 8 8 7 8 6 8 5 8 5 9 5 10 5 11 6 11 6 10 6 9 7 9 8 9 8 10 7 10 7 11 8 11 9 11 9 10 9 9 10 9 10 10 10 11 11 11 11 10 11 9 11 8 11 7 10 7 10 8 9 8 9 7 9 6 10 6 11 6 11 5 11 4 11 3 10 3 9 3 9 4 9 5 8 5 8 4 8 3 8 2 8 1 9 1 10 1 10 0 9 0 8 0 7 0 7 1 7 2 6 2 5 2 5 1 6 1 6 0 5 0 4 0 3 0 2 0 2 1 3 1 4 1 4 2 4 3 5 3 6 3 7 3 7 4 6 4 5 4 4 4 4 5 4 6 3 6 3 5 3 4 3 3 3 2 2 2 2 3 1 3 1 2 1 1 1 0 0 0 0 1 0 2 0 3 0 4 0 5 0 6 1 6 1 5 1 4 2 4 2 5 2 6 2 7 1 7 1 8 0 8 0 9 0 10

masukkan deskripsi gambar di sini

Kode:

I=raw_input().split('\n');X=len(I[0]);Y=len(I);R=range
def S(g=0,c=0,x=0,y=0):
    if y>=Y:return 0
    if g==0:g=[[-1]*X for i in R(Y)];c=[[-1]*X for i in R(Y)]
    o={'.':set(R(7)),'w':{1,2},'b':{3,4,5,6}}[I[y][x]].copy()
    o&={0,1,3,4}if y<1 or g[y-1][x]in[0,1,5,6]else{2,5,6}
    o&={0,2,4,5}if x<1 or g[y][x-1]in[0,2,3,6]else{1,3,6}
    if y>Y-2:o&={0,1,5,6}
    if x>X-2:o&={0,2,3,6}
    if y>0 and g[y-1][x]in[2,3,4]:
        if'b'==I[y][x]and g[y-1][x]!=2:return 0
        if'b'==I[y-1][x]:o&={2}
        elif'w'==I[y-1][x]and g[y-2][x]==2:o&={5,6}
    if x>0 and g[y][x-1]in[1,4,5]:
        if'b'==I[y][x]and g[y][x-1]!=1:return 0
        if'b'==I[y][x-1]:o&={1}
        elif'w'==I[y][x-1]and g[y][x-2]==1:o&={3,6}
    h=[r[:]for r in c]
    if y>0 and g[y-1][x]in[2,3,4]:
        if x>0 and g[y][x-1]in[1,4,5]:
            if c[y-1][x]==c[y][x-1]:
                if(6 not in o)+any(any(i!=c[y-1][x]and i!=-1 for i in r)for r in c)+any(I[v][u]!='.'and(v>y)+(u>x)for v in R(y,Y)for u in R(X)):return 0
                g[y][x]=6
                for v in R(y,Y):
                    for u in R(X):
                        if v!=y or u>x:g[v][u]=0
                for y in R(Y):
                    for x in R(X):
                        if g[y][x]>0:break
                f=[];d=-1;u,v=p,q=x,y
                while(u,v)!=(p,q)or-1==d:f+=[u,v];d=([0,{0,2},{1,3},{2,3},{0,3},{0,1},{1,2}][g[v][u]]-{(d+2)%4}).pop();i,j={0:(u+1,v),1:(u,v-1),2:(u-1,v),3:(u,v+1)}[d];u,v=i,j
                return f
            else:
                for v in R(y+1):
                    for u in R(X):
                        if h[v][u]==c[y][x-1]:h[v][u]=c[y-1][x]
                h[y][x]=c[y-1][x]
        else:h[y][x]=c[y-1][x]
    elif x>0 and g[y][x-1]in[1,4,5]:h[y][x]=c[y][x-1]
    else:h[y][x]=max(max(r)for r in c)+1
    for n in sorted(list(o))[::-1]:
        if n==0:h[y][x]=-1
        if x>X-2:i,j=0,y+1
        else:i,j=x+1,y
        g[y][x]=n;r=S(g,h,i,j)
        if r!=0:return r
    return 0
for i in S():print i,

Tidak Disatukan:

class Grid:
    def __init__(self,input):
        self.input = input.split('\n')
        self.x = len(self.input[0])
        self.y = len(self.input)
        self.options = {'.':{0,1,2,3,4,5,6},'w':{1,2},'b':{3,4,5,6}}

    def convert(self,grid):
        directions = [None,{0,2},{1,3},{2,3},{0,3},{0,1},{1,2}]

        for y in range(self.y):
            for x in range(self.x):
                if grid[y][x] != 0:
                    break

        chain = []
        start_pos = (x,y)
        dir = -1
        pos = start_pos
        while dir == -1 or pos != start_pos:
            chain.extend(pos)
            x,y = pos
            next_dir = (directions[grid[y][x]]-{(dir+2)%4}).pop()
            if next_dir == 0: nx,ny = x+1,y
            elif next_dir == 1: nx,ny = x,y-1
            elif next_dir == 2: nx,ny = x-1,y
            elif next_dir == 3: nx,ny = x,y+1
            dir = next_dir
            pos = (nx,ny)

        return chain

    def solve(self,grid=None,chain_ids=None,pos=(0,0)):
        x,y = pos
        if y >= self.y:
            return None

        if grid is None:
            grid = [[-1]*self.x for i in range(self.y)]
        if chain_ids is None:
            chain_ids = [[-1]*self.x for i in range(self.y)]

        options = self.options[self.input[y][x]].copy()
        if y == 0 or grid[y-1][x] in [0,1,5,6]:
            options &= {0,1,3,4}
        else:
            options &= {2,5,6}
        if y == self.y-1:
            options &= {0,1,5,6}

        if x == 0 or grid[y][x-1] in [0,2,3,6]:
            options &= {0,2,4,5}
        else:
            options &= {1,3,6}
        if x == self.x-1:
            options &= {0,2,3,6}

        if y != 0 and grid[y-1][x] in [2,3,4]:
            if self.input[y][x] == 'b' and grid[y-1][x] != 2:
                return None
            if self.input[y-1][x] == 'b':
                options &= {2}
            elif self.input[y-1][x] == 'w':
                if grid[y-2][x] == 2:
                    options &= {5,6}
        if x != 0 and grid[y][x-1] in [1,4,5]:
            if self.input[y][x] == 'b' and grid[y][x-1] != 1:
                return None
            if self.input[y][x-1] == 'b':
                options &= {1}
            elif self.input[y][x-1] == 'w':
                if grid[y][x-2] == 1:
                    options &= {3,6}


        new_chain_ids = [[i for i in row] for row in chain_ids]
        if y != 0 and grid[y-1][x] in [2,3,4]:
            if x != 0 and grid[y][x-1] in [1,4,5]:

                if chain_ids[y-1][x] == chain_ids[y][x-1]:
                    if 6 not in options:
                        return None

                    if any(any(i != chain_ids[y-1][x] and i != -1 for i in row) for row in chain_ids) or \
                    any(self.input[v][u] != '.' and (v!=y or u>x) for v in range(y,self.y) for u in range(self.x)):
                        return None

                    grid[y][x] = 6
                    for v in range(y,self.y):
                        for u in range(self.x):
                            if v != y or u > x: 
                                grid[v][u] = 0

                    return self.convert(grid)

                else:
                    for v in range(y+1):
                        for u in range(self.x):
                            if new_chain_ids[v][u] == chain_ids[y][x-1]:
                                new_chain_ids[v][u] = chain_ids[y-1][x]
                    new_chain_ids[y][x] = chain_ids[y-1][x]

            else:
                new_chain_ids[y][x] = chain_ids[y-1][x]
        elif x != 0 and grid[y][x-1] in [1,4,5]:
            new_chain_ids[y][x] = chain_ids[y][x-1]
        else:
            new_chain_ids[y][x] = max(max(row) for row in chain_ids)+1

        for n in sorted(list(options),key=lambda n: -n):
            grid[y][x] = n
            if n == 0:
                new_chain_ids[y][x] = -1

            if x == self.x-1:
                nx,ny = 0,y+1
            else:
                nx,ny = x+1,y

            result = self.solve(grid,new_chain_ids,(nx,ny))
            if result is not None:
                return result

input = """

.....w.b.w..
ww..b...b...
.w.....b....
...wbww..b.b
....b.......
w.w.........
..w......b.b
.....bb.....
.....b.....w
w.ww..b.....
...w......w.
b..w.....b..

""".strip()

def print_grid(grid):
    for y,row in enumerate(grid):
        s = ""
        for i in row:
            s += {-1:'xxx',0:'   ',1:'   ',2:' | ',3:'   ',4:'   ',5:' | ',6:' | '}[i]
        s += '\n'
        for x,i in enumerate(row):
            s += {-1:'x%sx',0:' %s ',1:'-%s-',2:' %s ',3:'-%s ',4:' %s-',5:' %s-',6:'-%s '}[i] % input.split('\n')[y][x]
        s += '\n'
        for i in row:
            s += {-1:'xxx',0:'   ',1:'   ',2:' | ',3:' | ',4:' | ',5:'   ',6:'   '}[i]
        s += '\n'
        print s

result = Grid(input).solve()
print result
KSab
sumber
@ Geobits Oh sepertinya saya tidak cukup membaca aturan. Jawaban yang diperbarui dengan apa yang saya yakini benar sekarang
KSab
Jalan baru terlihat bagus bagiku! +1
Geobits
1

Lua, 830 810 765 752 739 729 710

Menjalankan board1 dan board2 baik-baik saja, tetapi membutuhkan waktu di board3.

Ini bisa menghemat 9 byte dengan mengeluarkan setiap jalur, bukan hanya yang pertama ...

b={}s={0,0,0}R=table.insert Z=unpack for l in io.lines()do w=#l for i=1,w do
c=({b=1,w=2,['.']=3})[l:sub(i,i)]R(b,c)s[c]=s[c]+1 end end h=#b/w for e=0,w*h-1
do function g(p,d,X,t)local function G(I,r)T={Z(t)}a=b[I+1]T[a]=T[a]+1
P={Z(p)}D={Z(d)}R(P,I%w)R(P,I/w-I/w%1)R(D,r)l=#D for U=2,#p,2 do if
I==p[U-1]+w*p[U]then return end end if I==e then if T[1]==s[1]and T[2]==s[2]then
for k=1,l do K=D[k]M=D[(k-2)%l+1]N=D[k%l+1]O=D[(k+1)%l+1]if({K==N or K~=M or
N~=O,K~=N or(K==M and N==O)})[b[1+P[2*k-1]+w*P[2*k]]]then return end end
os.exit(print(table.concat(P,' ')))end else g(P,D,I,T)end end _=X%w<w-1 and
G(X+1,1)_=X/w-X/w%1<h-1 and G(X+w,2)_=X%w>0 and G(X-1,3)_=X/w-X/w%1>0 and
G(X-w,4)end g({},{},e,{0,0,0})end
lalunomor
sumber