在矩阵中查找蛇


32

挑战

给定一个二进制矩阵和一个二进制字符串,确定是否可以从矩阵的任何点开始找到该二进制字符串,然后在任何后续点向任意方向移动以形成二进制字符串。就是说,是否可以在矩阵内部找到折起的字符串?

字符串只能以90度或180度折叠(边缘连接;曼哈顿距离1),并且不能在任何一点重叠。

让我们来看下面的例子:

Matrix:

010101
111011
011010
011011

Snake: 0111111100101

这是一个真实的测试案例。我们可以看到蛇在以下位置折叠起来:

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

规则

  • 适用标准漏洞
  • 如果愿意,您可以将字符串的长度以及矩阵的宽度和高度作为输入
  • 您可以将二进制矩阵和二进制字符串作为多行字符串/字符串数组/换行连接的字符串/其他任何连接的字符串和字符串
  • 您可以将维度作为平面数组而不是几个参数
  • 您的程序必须在一分钟之内完成任何长度不超过10的字符串的任何5 x 5矩阵

局限性

  • 矩阵不一定是正方形
  • 字符串将为非空
  • 字符串长度可以为1
  • 该字符串所包含的正方形将不超过可用的正方形(即, len(string) <= width(matrix) * height(matrix)

测试用例

特鲁西

01010
10101
01010
10101
01010

0101010101010101010101010



01110
01100
10010
10110
01101

011111000110100



0

0



10
01

1010



100
010
001

100010001

虚假

00000
00000
00000
00000
00000

1



10101
01010
10101
01010
10101

11



100
010
001

111



10001
01010
00100
01010
10001

1000100010001000101010100

沙盒发布(已删除)
HyperNeutrino

4
或者:Bing Boggle!另外,您可以添加更多测试用例吗?
乔纳

1
在这种情况下,平坦,尖锐和圆形意味着什么?不是正方形的意思是宽度和高度可能不相等,或者数组可能是锯齿状的?
塔赫格

地球上是一个圆形阵列
Conor O'Brien

Answers:


13

Python 2中275个 271 264 249字节

  • 通过替换保存的四个字节-1H和去除一个切片操作([:])。
  • 多亏了Halvard Hummel节省了7个字节; 删除另一个切片操作([:]),使用多目标分配为访问的条目赋予值v not in "01"S=S[1:];M[y][x]=H;-> S=M[y][x]=S[1:];),然后从三元if / else切换为简单逻辑或(any(...)if S else 1-> not S or any(...))。
  • 如果你稍微延长你的定义truthyfalsey,你可以让这257字节长的解决方案ZeroDivisionError当发现蛇时,它会引发一个异常(),而在没有蛇时,它会返回一个空列表([]),这是两种不同的行为。
  • 由于user202729节省了十四个字节;打高尔夫球两排深复制
  • 保存一个字节;golfed not S orS<[1]orS==[]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])

在线尝试!

说明

Lambda函数,将矩阵作为字符串的二维列表("0""1"),将蛇作为一维列表,将矩阵维度作为两个整数。
lambda函数在矩阵中搜索与蛇的第一个元素匹配的条目。对于找到的每个匹配项,它都调用H矩阵的深层副本,而没有蛇的副本,矩阵尺寸和匹配项的位置。

H被调用时,它会删除S“第一个条目,并设置给定位置的矩阵进入的东西比别的"0", "1"。如果S'length为零,则返回True;当它递归地称自己为蛇时,它在矩阵的某个地方被发现。
如果S'length不为零,它将在四个基本方向上循环,测试该位置是否在矩阵中,并将该位置处的matrix'元素与的第一个元素进行比较S,如果匹配,则递归调用自身。
H的返回值集中在堆栈帧中,始终检查是否至少有一个函数找到了可能的蛇。

格式化输出

我扩充了程序,还输出了蛇滑行的路径(如果有的话)。它使用与问题相同的ASCII输出设计。TIO链接



1
@HalvardHummel谢谢;特别是用于发现多余的切片操作。
乔纳森·弗雷希

@ user202729您认为m[:]for〜> m*1for吗?可能会工作。
乔纳森·弗雷希

@ user202729谢谢,链接的提示起作用了,因为我认为这需要深入的复制。
乔纳森·弗雷希

9

的JavaScript(ES6),138 134

与@Neil的区别不大,但是还有什么呢?

输入:矩阵为多行字符串,二进制字符串,宽度(不计算换行符)

注意:递归函数中的逻辑r有些倒转以节省几个字节

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

少打高尔夫球

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

测试

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字节

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

将矩阵作为换行符分隔的字符串,将蛇作为字符串,并将宽度作为整数(整数)。松散地基于@JonathanFrech的答案。


4

数学,180个 156 141 153 138 136 104字节

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

输入示例

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

说明

  1. GridGraph@{##4}Graph用于与由边缘连接的相邻顶点,其尺寸顶点的网格对象{##4}-即,{#4,#5}或者{width,height}
  2. 我们遍历所有起始顶点x(编号11##4 = width*height),所有终止顶点y以及所有p长度最大为#3x到的路径y
  3. 对于每个这样的路径,""<>Part[Join@@#,p]提取矩阵的相应字符并将它们放入字符串中。
  4. 我们还包括矩阵本身,矩阵的字符都是可以在其中找到的所有长度为1的字符串。
  5. 我们看到这些字符串之一是否匹配s,可以在所有级别进行搜索,因为这是我们构建的一个非常多维的列表。

注意:#3{#3-1}in 代替FindPath,以便我们只找到长度正确的路径,这在速度方面有很大的改进-但要多花4个字节。


-24字节:以事物的维度作为输入

-15个字节:使用StringPartStringJoin正确

+12个字节:固定长度为1的情况

-15个字节:...

-2字节:将矩阵的大小作为数组输入

-32字节:使用Table遍历路径可以避免使用Function,而使用则MemberQ[...,s,All]可以在处理长度为1的蛇时将矩阵仅粘贴到表上。


3

C#(.NET核心)346个 341 336 302 297字节

(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;}}

在线尝试!

打高尔夫球p增加了5个字节

通过保留蛇的长度并从蛇的尾部开始并删除不必要的空间,可以节省5个字节

通过正确阅读挑战并看到我可以输入矩阵的高度和宽度,可以节省34个字节

保存了5个字节,单元素测试用例失败,并且该修复程序很有用

不打高尔夫球

(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; 
    }
}

打高尔夫球的开始是要消除所有不必要的空白...
Jonathan Frech

if(...)return true;-> return ...;
乔纳森·弗雷希

@JonathanFrech同意,但我这样保留它,以便其他人可以更轻松地阅读它,直到我有机会回到它上面(明天的某个时候)。
Ayb4btu

@JonathanFrech不起作用,b[y,x]需要在某些时候重置。(也很抱歉在我的回答中拼错了您的名字。)
尼尔(Neil

我是说if(N(x,y,0)>0)return 0<1;; 的首次出现return
乔纳森·弗雷希

1

Kotlin,413字节

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

美化

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

测试

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")
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.