Tìm rắn trong ma trận


32

Thử thách

Đưa ra một ma trận nhị phân và một chuỗi nhị phân, xác định xem chuỗi nhị phân đó có thể được tìm thấy bắt đầu từ bất kỳ điểm nào trong ma trận hay không và di chuyển theo bất kỳ hướng nào tại bất kỳ điểm tiếp theo nào để tạo thành chuỗi nhị phân. Đó là, chuỗi có thể được tìm thấy gấp lại tuy nhiên bên trong ma trận?

Chuỗi chỉ có thể được gấp lại ở 90 độ hoặc 180 độ (kết nối cạnh; Manhattan Khoảng cách 1) và không thể tự chồng lên nhau tại bất kỳ điểm nào.

Thí dụ

Hãy lấy ví dụ sau:

Matrix:

010101
111011
011010
011011

Snake: 0111111100101

Đây là một trường hợp thử nghiệm trung thực. Chúng ta có thể thấy con rắn gấp lại ở vị trí sau:

0-1 0 1 0 1
  |
1 1 1-0 1 1
  | | |   |
0 1 1 0-1-0
  | |
0 1-1 0 1 1

Quy tắc

  • Áp dụng sơ hở tiêu chuẩn
  • Bạn có thể lấy độ dài của chuỗi và chiều rộng và chiều cao của ma trận làm đầu vào nếu bạn muốn
  • Bạn có thể lấy ma trận nhị phân và chuỗi nhị phân làm chuỗi đa chuỗi / mảng chuỗi / chuỗi tham gia newline / bất kỳ chuỗi nào khác đã tham gia và chuỗi
  • Bạn có thể lấy kích thước dưới dạng một mảng phẳng thay vì một vài đối số
  • Chương trình của bạn phải hoàn thành cho bất kỳ ma trận 5 x 5 nào với bất kỳ chuỗi nào có độ dài tối đa 10 trong một phút

Hạn chế

  • Ma trận không nhất thiết phải là hình vuông
  • Chuỗi sẽ không trống
  • Chuỗi có thể dài 1
  • Chuỗi sẽ không chứa nhiều ô vuông hơn mức có sẵn (nghĩa là len(string) <= width(matrix) * height(matrix)

Các trường hợp thử nghiệm

Sự thật

01010
10101
01010
10101
01010

0101010101010101010101010



01110
01100
10010
10110
01101

011111000110100



0

0



10
01

1010



100
010
001

100010001

Giả

00000
00000
00000
00000
00000

1



10101
01010
10101
01010
10101

11



100
010
001

111



10001
01010
00100
01010
10001

1000100010001000101010100


4
Hoặc: Nháy mắt nhị phân! Ngoài ra, bạn có thể thêm một vài trường hợp thử nghiệm?
Giô-na

1
Làm phẳng, sắc nét và tròn có nghĩa là gì trong bối cảnh này? Không vuông có nghĩa là chiều rộng và chiều cao có thể không bằng nhau, hoặc mảng có thể bị lởm chởm?
Tahg

những gì trên trái đất là một mảng tròn
Conor O'Brien

Câu trả lời:


13

Python 2 , 275 271 264 249 byte

  • Đã lưu bốn byte bằng cách thay thế -1bằng Hvà loại bỏ một thao tác cắt ( [:]).
  • Đã lưu bảy byte nhờ Halvard Hummel ; xóa một thao tác cắt lát khác ( [:]), sử dụng phép gán nhiều mục tiêu để cung cấp một mục nhập được truy cập một giá trị v not in "01"( S=S[1:];M[y][x]=H;-> S=M[y][x]=S[1:];) và chuyển từ một ternary if / other sang một logic đơn giản hoặc ( any(...)if S else 1-> not S or any(...)).
  • Nếu bạn phần nào mở rộng định nghĩa của bạn về sự thậtchim ưng , bạn có thể cho phép giải pháp dài 256 byte này . Nó đưa ra một ngoại lệ ( ZeroDivisionError) khi con rắn được tìm thấy và trả về một danh sách trống ( []) khi không tìm thấy con rắn nào, đó là hai hành vi khác biệt.
  • Đã lưu mười bốn byte nhờ user202729 ; chơi golf hai bản sâu
  • Đã lưu một byte; golfed not S orđến S<[1]or~ S==[]or.
lambda M,S,w,h:any(H(eval(`M`),S,w,h,x,y)for y in range(h)for x in range(w)if S[0]==M[y][x])
def H(M,S,w,h,x,y):S=M[y][x]=S[1:];return S<[1]or any(H(eval(`M`),S,w,h,x+X,y+Y)for X,Y in[(~0,0),(1,0),(0,~0),(0,1)]if~0<x+X<w>0<=y+Y<h!=S[0]==M[y+Y][x+X])

Hãy thử trực tuyến!

Giải trình

Hàm Lambda lấy trong ma trận dưới dạng danh sách các chuỗi hai chiều (hoặc "0"hoặc "1"), con rắn làm danh sách một chiều và kích thước ma trận là hai số nguyên.
Hàm lambda tìm kiếm ma trận cho các mục khớp với phần tử đầu tiên của con rắn. Đối với mỗi trận đấu được tìm thấy, nó gọi Hvới một bản sao sâu của ma trận, không có bản sao của con rắn, kích thước ma trận và vị trí của trận đấu.

Khi Hđược gọi, nó sẽ xóa Smục nhập đầu tiên và đặt mục nhập ma trận của vị trí đã cho thành một mục khác "0", "1". Nếu S'độ dài bằng 0, nó sẽ trả về True; khi nó tự gọi mình một cách đệ quy, con rắn đã được tìm thấy ở đâu đó trong ma trận.
Nếu S'độ dài khác không, nó lặp qua bốn hướng chính, kiểm tra xem vị trí đó có trong ma trận hay không, so sánh phần tử của ma trận tại vị trí đó với phần tử đầu tiên Svà - nếu nó khớp - gọi chính nó theo cách đệ quy.
HCác giá trị trả về được đưa lên các khung ngăn xếp, luôn kiểm tra xem có ít nhất một hàm tìm thấy một con rắn có thể không.

Định dạng đầu ra

Tôi đã tăng cường chương trình của mình để xuất ra đường dẫn con rắn (nếu có). Nó sử dụng thiết kế đầu ra ASCII giống như câu hỏi. Liên kết TIO .



1
@HalvardHummel Cảm ơn; đặc biệt là để phát hiện các hoạt động cắt lát thừa.
Jonathan Frech

@ user202729 Bạn nghĩ sao m[:]for~> m*1for? Có thể làm việc.
Jonathan Frech

@ user202729 Cảm ơn, mẹo được liên kết hoạt động vì tôi nghĩ rằng điều này cần một bản sao sâu.
Jonathan Frech

9

JavaScript (ES6), 138 134

Không quá khác biệt với @ Neil, nhưng nó có thể là gì khác?

Đầu vào: ma trận dưới dạng chuỗi nhiều dòng, chuỗi nhị phân, chiều rộng (không tính dòng mới)

NB: logic trong hàm đệ quy rcó phần bị đảo ngược để lưu một vài byte

(m,s,w)=>[...m].some((c,p,m,r=(p,o)=>s[m[p]=r,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))

Ít chơi gôn

(m,s,w)=>(
  m=[...m],
  r= (p, o) => 
    (m[p] = -w, s[o])
    && (
         [~w, -~w, 1, -1].every( d =>
            m[d+=p] != s[o] || r(d, o+1)
         )
         && (m[p]=s[o-1])
    ),
  m.some((c,p) =>c == s[0] && !r(p,1))
)

Kiểm tra

var F=
(m,s,w)=>[...m].some((c,p,m,r=(p,o)=>s[m[p]=r,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))

// this slightly modified version tracks the path
var Mark=
(m,s,w)=>(m=[...m]).some((c,p,m,r=(p,o)=>s[m[p]=-o,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))
?m.map((c,p)=>c<-1?'.───│┘└.│┐┌.│'[((m[p-1]-c)**2<2)+((m[p+1]-c)**2<2)*2+((m[p+~w]-c)**2<2)*4+((m[p-~w]-c)**2<2)*8]:c<0?'*':c).join``:''

function go()
{
  O.textContent =F(M.value, S.value, M.value.search('\n'))+'\n\n'
  +Mark(M.value, S.value, M.value.search('\n'))
}

go()
#M {width:100px; height:100px }
<textarea id=M>010101
111011
011010
011011</textarea><br>
<input id=S value='0111111100101' oninput='go()'>
<button onclick='go()'>go</button>
<pre id=O></pre>


6

JavaScript (ES6), 149 byte

(m,s,w)=>[...m].some((c,i)=>c==s[0]&&g(m,s,i),g=(m,s,i)=>!(s=s.slice(1))||[~w,-1,1,-~w].some(o=>m[o+=i]==s[0]&&g(m.slice(0,i)+' '+m.slice(i+1),s,o)))

Lấy ma trận dưới dạng một chuỗi được phân định bằng dòng mới, con rắn là một chuỗi và chiều rộng (dưới dạng một số nguyên). Dựa vào câu trả lời của @ JonathanFrech.


4

Toán học, 180 156 141 153 138 136 104 byte

MemberQ[#|Table[""<>Part[Join@@#,p],{x,1##4},{y,1##4},{p,FindPath[GridGraph@{##4},x,y,#3,All]}],#2,All]&

Ví dụ đầu vào

[{{"1","1","1","1","1"},{"0","0","0","0","0"}},"10011001",8,5,2]

Giải trình

  1. GridGraph@{##4}là một Graphđối tượng cho một lưới các đỉnh với các đỉnh liền kề được kết nối bởi các cạnh, với các kích thước {##4}- đó là, {#4,#5}hoặc {width,height}.
  2. Chúng tôi lặp qua tất cả các đỉnh bắt đầu x(đánh số 1để 1##4 = width*height), tất cả các đỉnh kết thúc y, và tất cả các đường dẫn pcó độ dài tối đa là #3từ xđể y.
  3. Đối với mỗi đường dẫn như vậy, ""<>Part[Join@@#,p]trích xuất các ký tự tương ứng của ma trận và đặt chúng thành một chuỗi.
  4. Chúng tôi cũng bao gồm chính ma trận, có các ký tự là tất cả các chuỗi có độ dài 1 có thể được tìm thấy trong đó.
  5. Chúng tôi thấy nếu một trong các chuỗi này khớp s, tìm kiếm ở tất cả các cấp vì đây là danh sách rất đa chiều mà chúng tôi đã tạo.

Lưu ý: Thay thế #3bằng {#3-1}trong FindPath, để chúng tôi chỉ tìm thấy các đường dẫn có độ dài chính xác, là một cải tiến rất lớn về tốc độ - nhưng tốn thêm 4 byte.


-24 byte: lấy kích thước của mọi thứ làm đầu vào

-15 byte: sử dụng StringPartStringJoinđúng cách

+12 byte: sửa trường hợp length-1

-15 byte: ...

-2 byte: lấy kích thước của ma trận làm đầu vào dưới dạng một mảng

-32 byte: sử dụng Tableđể lặp lại trên đường dẫn cho phép chúng ta tránh sử dụng Functionvà việc sử dụng MemberQ[...,s,All]cho phép chúng ta chỉ cần sắp xếp ma trận lên bàn khi xử lý rắn có độ dài 1.


3

C # (.NET Core) , 346 341 336 302 297 byte

(m,h,w,s,l)=>{for(int y=0;y<h;y++)for(int x=0;x<w;x++)if(N(x,y,l-1))return 0<1;return 1<0;bool N(int x,int y,int p){if(p<0)return 0<1;if(y<0|x<0|y==h|x==w||m[y,x]>1||s[p]!=m[y,x])return 1<0;int g=m[y,x];m[y,x]=2;if(N(x,y-1,--p)||N(x-1,y,p)||N(x,y+1,p)||N(x+1,y,p))return 0<1;m[y,x]=g;return 1<0;}}

Hãy thử trực tuyến!

5 byte cứu bởi chơi golf các pincrement

5 byte được lưu bằng cách lấy chiều dài con rắn và bắt đầu từ đuôi của nó và xóa một khoảng trống không cần thiết

34 byte được lưu bằng cách đọc đúng thử thách và thấy tôi có thể nhận chiều cao và chiều rộng của ma trận

Đã lưu 5 byte, trường hợp kiểm tra phần tử đơn bị lỗi và cách khắc phục có lợi

Ung dung

(m,h,w,s,l)=>{
    // Go through every potential starting point
    for(int y=0; y<h; y++)
        for(int x=0; x<w; x++)
            if(N(x,y,l-1)) // start the recursive steps
                return 0<1; // return true if N returns true, otherwise check the next element

    return 1<0; // return false as the snake doesn't fit into the matrix

    // C#7 local function in a Func
    bool N(int x, int y, int p)
    {
        // if there is no more snake to fit return true
        if(p<0)
            return 0<1;

        // if m element has part of the snake or 
        // snake part doesn't match matrix element then return false
        if(y<0 | x<0 | y==h | x==w || m[y,x]>1 || s[p] != m[y,x])
            return 1<0;

        // hold the current matrix element
        int g=m[y,x];
        // set the current matrix element to 2 to indicate it has a part of the snake
        m[y,x]=2;

        // check each of the four neighbours and recurse down that neighbour 
        // except if they are outside the matrix
        if(N(x,y-1,--p) ||
           N(x-1,y,p) ||
           N(x,y+1,p) ||
           N(x+1,y,p))
               return 0<1; // return true if remainder of the snake fits into the matrix

        // if snake doesn't fit then set the matrix element as not having part of the snake
        m[y,x]=g;
        // return false to indicate this neighbour direction doesn't fit the snake
        return 1<0; 
    }
}

Một khởi đầu chơi gôn sẽ là loại bỏ tất cả các khoảng trắng không cần thiết ...
Jonathan Frech

if(...)return true;-> return ...;.
Jonathan Frech

@JonathanFrech Đồng ý, nhưng tôi đã để nó như thế để cho phép người khác đọc nó dễ dàng hơn một chút cho đến khi tôi có cơ hội quay lại với nó (đôi khi vào ngày mai).
Ayb4btu

@JonathanFrech Không hoạt động, b[y,x]cần phải được thiết lập lại tại một số điểm. (Cũng xin lỗi vì đã viết sai tên của bạn trong câu trả lời của tôi.)
Neil

Ý tôi là if(N(x,y,0)>0)return 0<1;; sự xuất hiện đầu tiên của return.
Jonathan Frech

1

Kotlin , 413 byte

var x:(Array<Array<Char>>,String)->Boolean={b,s->fun f(s:String,x:Int,y:Int):Boolean{if(b[x][y]!=s[0])
return 0>1
if(s.length<2)
return 1>0
val v=b[x][y]
b[x][y]='Z'
try{return(-1..1).map{x+it}.flatMap{t->(-1..1).map{y+it}.map{t to it}}.filter{(X,Y)->(x-X)*(x-X)+(y-Y)*(y-Y)==1&&X in b.indices&&Y in b[0].indices&&f(s.substring(1),X,Y)}.any()}finally{b[x][y]=v}}
b.indices.any{x->(0..b[0].size-1).any{f(s,x,it)}}}

Làm đẹp

var x: (Array<Array<Char>>, String) -> Boolean = { b, s ->
    fun f(s: String, x: Int, y: Int): Boolean {
        if (b[x][y] != s[0])
            return 0 > 1
        if (s.length < 2)
            return 1 > 0
        val v = b[x][y]
        b[x][y] = 'Z'
        try {
            return (-1..1).map{ x + it }
                    .flatMap { t -> (-1..1).map{y+it}.map { t to it } }
                    .filter { (X, Y) ->
                        (x - X)*(x - X) + (y - Y)*(y - Y) == 1 &&
                                X in b.indices && Y in b[0].indices &&
                                f(s.substring(1), X, Y) }
                    .any()
        } finally {
            b[x][y] = v
        }
    }
    b.indices.any { x -> (0..b[0].size - 1).any { f(s, x, it) } }
}

Kiểm tra

var x:(Array<Array<Char>>,String)->Boolean={b,s->fun f(s:String,x:Int,y:Int):Boolean{if(b[x][y]!=s[0])
return 0>1
if(s.length<2)
return 1>0
val v=b[x][y]
b[x][y]='Z'
try{return(-1..1).map{x+it}.flatMap{t->(-1..1).map{y+it}.map{t to it}}.filter{(X,Y)->(x-X)*(x-X)+(y-Y)*(y-Y)==1&&X in b.indices&&Y in b[0].indices&&f(s.substring(1),X,Y)}.any()}finally{b[x][y]=v}}
b.indices.any{x->(0..b[0].size-1).any{f(s,x,it)}}}

data class Test(val board: String, val snake: String, val output: Boolean)

val tests = listOf(
        Test("""01010
            |10101
            |01010
            |10101
            |01010""", "0101010101010101010101010", true),
        Test("""01110
            |01100
            |10010
            |10110
            |01101""", "011111000110100", true),
        Test("""0""", "0", true),
        Test("""10
            |01""", "1010", true),
        Test("""100
            |010
            |001""", "100010001", true),
        Test("""00000
            |00000
            |00000
            |00000
            |00000""", "1", false),
        Test("""10101
            |01010
            |10101
            |01010
            |10101""", "11", false),
        Test("""100
            |010
            |001""", "111", false),
        Test("""10001
            |01010
            |00100
            |01010
            |10001""", "1000100010001000101010100", false)
)

fun main(args: Array<String>) {
    tests.filter {(board, snake, expected) ->
        val boardR = board.trimMargin().lines().map { it.toCharArray().toTypedArray() }.toTypedArray()
        val result = x(boardR, snake)
        result != expected
    }.forEach { throw AssertionError(it) }
    println("Test Passed")
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.