验证皇后难题


16

如果您不知道国际象棋中的皇后是什么,那没关系。这只是一个名字:)

您的输入将是一个任意宽度和高度的正方形,其中包含一些皇后。输入板看起来像这样(此板的宽度和高度为8):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

该板上有8个皇后。如果此处有7个,1个或10个,则该董事会将无效。

在这里,我们用a .表示空白,用Qa表示女王。您也可以选择使用任何非空白字符。

可以验证此输入有效,并且您应该打印(或返回)真实值(如果无效,则应打印(或返回)虚假值)。这是有效的,因为女王/王后不在同一行,列,对角线或反对角线中

示例(不要在方括号中输出内容):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

1

...Q.
Q....
.Q...
....Q
..Q..

0

Q.
Q.

0

..Q
...
.Q.

0 (this is 0 because there are only 2 queens on a 3x3 board)


..Q.
Q...
...Q
.Q..

1

Q

1 (this is valid, because the board is only 1x1, so there's no queen that can take another)

让我强调,只有在以下情况下输入才有效 在与另一行相同的行,列,对角线或反对角线中没有女王/王后时

规则

  • 您将永远不会收到空的输入
  • 如果输入的皇后数量少于木板区域的平方根,则无效。
  • 请注意,对于2x2或3x3电路板没有有效的解决方案,但是每隔一个尺寸的正方形都有一个解决方案板(宽度和高度均为自然数)。
  • 根据PPCG规则,输入可以采用任何合理的格式
  • 输入将始终是平方
  • 在示例中,我使用了1和0,但是您可以使用任何真实或虚假的值(例如Why yes, sir, that is indeed the caseWhy no, sir, that is not the case

因为这是,所以最短的代码获胜!



1
{(x, y, v)}具有v[., Q]一个有效的输入格式?
PidgeyUsedGust

@DuctrTape我认为这没有多大意义。
Okx

2
@Okx换句话说,他们正在询问接收作为输入的坐标和值列表。例如:(0, 0, Q), (0, 1, .), (1, 0, Q), (1, 1, .)将是第三个测试用例。
Mego

我可以带没有换行符的字符串吗?
泰特斯

Answers:


7

蜗牛,14字节

&
o.,\Q!(z.,\Q

在线尝试!

没有什么比2D模式匹配语言更适合2D决策问题了。:)

说明

&第一行上的匹配模式选项需要在第二行上的图案,以从输入每一个可能的位置相匹配。如果是这样,程序将打印1,否则将打印0

至于模式本身,请注意)结尾处有一个隐式。

o       ,, Move in any orthogonal direction (up, down, left or right).
.,\Q    ,, Make sure that there's a Q somewhere in that direction from the
        ,, starting position of the match.
!(      ,, After finding the Q, make sure that the following part _doesn't_ match:
  z     ,,   Move in any orthogonal or diagonal direction.
  .,\Q  ,,   Try to find another Q in a straight line.
)

从否定先行开始最容易理解为什么这样做:通过确保没有Q一条直线与Q我们已经找到的另一条直线,我们确保不超过N个皇后(否则,排成两列,而找不到另一个女王就不可能找到这些女王。然后第一部分,确保从任何位置都可以在正交方向上到达一个女王/王后,确保正好有N个女王/王后。如果一个人不见了,那将是一排又一排,没有女王。从这些点的交点开始,仅通过正交方向就不可能找到女王。


6

果冻,17或15个字节

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ

在线尝试!

用途为女王和¹空白空间。(这主要是禁止将输入作为数组使用的结果,因为它强制输入为字符串;在Jelly中很难将字符串转换为整数,最简单的方法是求值,结果是用1和1代替0,使用“加1”( )和“添加0”( ¹)有可能省略一些和与图的指令,因为我们可以通过评估指望它在列表中的皇后)的truthy和falsey值是果冻的正常10

编辑:自从我编写此答案以允许将输入作为矩阵以来,问题已经更改。这允许删除前导Ỵµ,节省2个字节。它也可能允许将输入格式更改为更普通的形式,用S求和而不是V求值,但是我不认为这样可以节省字节,我有点喜欢这种时髦的格式。

说明

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ
Ỵ                    Split on newlines.
 µ                   Set this value as the default for missing arguments.
     ;  ;            Concatenate the following three values:
  UŒD                - the antidiagonals;
      ŒD             - the diagonals;
         Z           - and the columns.
          V          Evaluate (i.e. count the queens on) all of those.
           Ṁ         Take the largest value among the results.
            ;V       Append the evaluation (i.e. queen count) of {each row}.
              =1     Compare each value to 1.
                Ṃ    Take the minimum (i.e. most falsey) result.

因此,基本思想是,我们确保每个对角,对角和圆柱上最多有一个女王。每排恰好有一个女王。这些条件共同足以要求四类线中的每条线上最多有一个皇后,而皇后的数量等于木板的边长。

顺便说一句,Jelly可能可以使用内置的对角线对角线,但AFAICT似乎没有它,因此我需要先确定一下板面,然后再取对角线。

另一个有趣的注意事项是,更改=1ṂE(全部等于)会给出广义的n皇后检查器,该检查器还将接受n × n的棋盘,其中每行,列,对角线和反对角线包含不超过k个皇后,并且该棋盘包含KN皇后。将k限制为等于1实际上会花费两个字节。


现在更新了规则,“根据PPCG规则,输入可以采用任何合理的格式”,这应该使其更短:)编辑-我看到您注意到了。
乔纳森·艾伦

5

八度,57 70 67 51 52字节

使用@ 1节省了1个字节,flip而不是rot90感谢@LuisMendo,但是在1x1情况下发现了一个错误

@(A)all(sum([A A' (d=@spdiags)(A) d(flip(A))],1)==1)

将输入作为二进制矩阵,其中1代表皇后,0代表空白。

创建一个匿名函数,该函数首先连接输入矩阵及其转置。

spdiags创建一个与参数行数相同的矩阵,对角线变为列(必要时零填充),因此spdiags将输入矩阵连接起来以获得对角线,然后spdiags将矩阵水平翻转以获得反对角线。

现在取连接矩阵的每一列的总和,并确保每一列正好是1。

样品在ideone上运行


我想你可以使用flip,而不是rot90
路易斯Mendo

@LuisMendo是的,也可以。谢谢!
烧杯

另外,你不能避免all()吗?
路易斯·门多

@LuisMendo Ugh ...可能...但是必须等到晚餐后才来;)
烧杯

4

玛特38 34字节

@beaker减少了 4个字节

sG!sGt&n_w&:&XdsGP5M&Xdsv2<GnGzU=*

输入是零和一的2D数组,使用分号作为行分隔符。

这将输出一的列向量为真,而包含至少一个零的列向量为伪。

在线尝试!页脚代码是if演示真实性或欺诈性的分支。

验证所有测试用例

说明

s      % Input binary matrix implicitly. Sum of columns. Gives a row vector
G!     % Paste input again. Transpose
s      % Sum of columns (rows in the original matrix). Gives a row vector
G      % Paste input again
t&n    % Duplicate. Push number of rows and number of columns (will be equal)
_w     % Negate, flip
&:     % Binary range. Gives [-n -n+1 ... n] for input of size n×n
&Xd    % Get diagonals -n through n. This gives all diagonals as colums
s      % Sum of each column (diagonals of original matrix). Gives a row vector
GP     % Paste input again. Flip vertically
5M     % Push [-n -n+1 ... n] again
&Xd    % Get diagonals -n through n (anti-diagonals of original matrix)
s      % Sum of each column. Gives a row vector
v      % Concatenate everything into a column vector
2<     % True for elements that are less than 2
Gn     % Paste input again. Number of elements
Gz     % Paste input again. Number of nonzeros (i.e. of queens)
U      % Square
=      % True if equal
*      % Mutiply, element-wise

现在您可以保存2个字节,您可以将二进制矩阵作为输入。
烧杯,

2

J,37个字节

(+/&,=#)*1=[:>./+//.,+//.&|.,+/,+/&|:

以布尔矩阵为参数的匿名函数序列。

在线尝试!

( +/总和&,拆纱=等于#行的理货)

* 和(点亮时间)

1一个=等于[:>./最大的

+//.对角线的总和,和(照度连接到)

+/总和/.对角&|.反向,

+/整个资金,

+/该款项&|:转置


2

SnakeEx,67字节

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}
e:.$
q:_*Q_*$
n:_+$

用途 _代替.输入。返回1个或更多符合条件的匹配项,返回0符合条件的匹配项。您可以在标题的链接中找到在线翻译。

说明

SnakeEx是2D模式匹配挑战中的一种语言。它定义了在网格匹配内容周围移动的“蛇”。蛇可以产生其他蛇,这使得它的语言非常强大。

让我们从头开始看这个程序。

n:_+$

这定义了一条蛇n,该蛇匹配1个或多个下划线,然后匹配网格的边缘。请注意,这可以是8个基本方向中的任何一个-该方向是在生成蛇时确定的。

q:_*Q_*$

n上面类似,它定义q为匹配任意数量的下划线,单个Q,任意数量的下划线和网格边缘的蛇。换句话说,一行/列/对角线中只有一个女王。

e:.$

e 是与一个字符和网格边缘匹配的蛇。

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}

主蛇m 使用这些构件来检查整个木板。从概念上讲,它围绕网格的外部边缘运行,生成其他蛇来检查所有列和行是否恰好有一个皇后,并且所有对角线最多也有一个皇后。如果任何生成的蛇不匹配,则整个匹配都会失败。让我们分解一下。

  • ( )%{4}将括号内的内容运行4次,每边一次。(在下面的内容中,描绘出特定的一面很有帮助-例如,网格的顶部边缘从左上角开始向右移动。)
  • {q<>}q以与主蛇移动相同的方向生成一条蛇。这验证了当前边是否符合“恰好一个女王”规则。请注意,生成的蛇不会移动主蛇的匹配指针,因此我们仍处于边缘的起点。
  • ( )* 匹配括号内的0个或多个。
  • {q<R>}产生一条q从主蛇方向向右转的蛇。(例如,如果主蛇沿上边缘向右移动,则该蛇向下移动。)这将检查每列/每行。
  • [ ] 匹配方括号内的任一选项:
    • {q<RF>}生成一条从主蛇的方向q向右(即向右RF向右)旋转45度的蛇。该q如果对角线只包含一个女王蛇相匹配。
    • {n<RF>}n而是产生一条蛇。该n如果对角线不包含皇后蛇相匹配。
  • . 匹配任何字符,向前移动匹配指针。
  • 在检查了尽可能多的水平线和对角线之后,我们通过生成来验证我们是否处于边缘 {e<>}
  • 最后,<R>将主蛇向右转,准备与下一条边缘匹配。

奇怪的东西

  • 程序中没有任何内容可确保匹配从外部开始。实际上,真实的测试用例会产生多个匹配项,其中一些匹配项是从内部某个地方开始的。尽管如此,我尝试过的所有虚假案例均未产生任何误报。
  • 如果我在正确阅读语言规范,则应该可以使用X(在所有对角线方向分支)代替RF。不幸的是,在线解释器说这是语法错误。我也尝试过*(四面八方),但这使翻译器挂了。
  • 从理论上讲,_*Q?_*$应该使用类似的方法来匹配对角线中的“最多一个女王”,但这也使解释程序挂了。我的猜测是,空匹配的可能性会引起问题。

2

Ruby,120个字节

Lambda函数基于原始规范,需要以字符串形式输入。

->s{t=k=0
a=[]
s.bytes{|i|i>65&&(a.map{|j|t&&=((k-j)**4).imag!=0};a<<k)
k=i<11?k.real+1:k+?i.to_c}
t&&~a.size**2>s.size}

将Q转换为复数并将它们彼此相减。如果任意两个皇后座标之间的坐标差是水平,垂直或对角线,则将其提高到4的幂将产生一个实数,并且该排列无效。

取消测试程序

f=->s{                                 #Take input as string argument.
  t=k=0                                #k=coordinate of character. t=0 (truthy in ruby.)
  a=[]                                 #Empty array for storing coordinates.
  s.bytes{                             #Iterate through all characters as bytes.
    |i|i>65&&(                         #If alphabetical, compare the current value of k to the contents of a
      a.map{|j|t&&=((k-j)**4).imag!=0} #If k-j is horizontal, vertical or diagonal, (k-j)**4 will be real and t will be false
      a<<k)                            #Add the new value of k to the end of a.
    k=i<11?k.real+1:k+?i.to_c          #If not a newline, increment the imaginary part of k. If a newline, set imaginary to 0 and increment real
  }                                    #s.size should be a*a + a newlines. ~a.size = -1-a.size, so ~a.size**2 = (a.size+1)**2
t&&~a.size**2>s.size}                  #compare a.size with s.size and AND the result with t. Return value. 


p f["...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q.."]

p f["...Q.
Q....
.Q...
....Q
..Q.."]

p f["Q.
Q."]

p f["..Q
...
.Q."]

p f["..Q.
Q...
...Q
.Q.."]

p f["Q"]

2

Python 3中232个 200 155字节

d=1
f=input()
Q=[]
for i in f:d=[0,d][i.count('Q')==1];Q+=[(len(Q),i.index('Q'))]
print[0,d][sum(k[1]==i[1]or sum(k)==sum(i)for k in Q for i in Q)==len(Q)]

在线尝试!

-32字节,感谢@beaker注意到输入规范的更改;我将语言从Python 3更改为2,因此允许我使用input输入作为字符串数组或字符数组数组。

-45字节感谢@Leaky Nun


输入的要求已经放宽,如果有帮助的话。
烧杯,

@beaker好的,谢谢。我将输入改为字符串数组。感谢您指出了这一点!
HyperNeutrino


1

JavaScript(ES6),115个字节

a=>!a.some((b,i)=>b.some((q,j)=>q&&h[i]|v[j]|d[i+j]|e[i-j]|!(h[i]=v[j]=d[i+j]=e[i-j]=1))|!h[i],h=[],v=[],d=[],e=[])

取消高尔夫:

function queens(arr) {
    horiz = [];
    vert = [];
    diag = [];
    anti = [];
    for (i = 0; i < arr.length; i++) {
        for (j = 0; j < arr.length; j++) {
            if (arr[i][j]) { // if there is a queen...
                if (horiz[i]) return false; // not already on the same row
                if (vert[j]) return false; // or column
                if (diag[i + j]) return false; // or diagonal
                if (anti[i - j]) return false; // or antidiagonal
                horiz[i] = vert[j] = diag[i + j] = anti[i - j] = true; // mark it
            }
        }
        if (!horiz[i]) return false; // fail if no queen in this row
    }
    return true;
}

0

Ruby,155个字节

->x{(y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2}).zip(y.rotate).map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}.inject(:+)*2==(s=x.size)*~-s}

这太可怕了,所以下面我的高尔夫球版本要少一些

->x{
    (y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2})
    .zip(y.rotate)
    .map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}
    .inject(:+)*2==(s=x.size)*~-s
}

这是相同的代码,但是带有一些换行符以区分发生了什么。

代码本身是一个匿名lambda函数,它接受字符串数组(x格式)["..Q", "Q..", ".Q."]

第一行将每个字符串映射到该字符串中Q字符的索引。如果没有Q字符,则将其替换为-2 1。这个新的索引数组分配给变量y

下一行压缩此索引数组,其自身偏移一个(旋转)。这导致成对的连续索引对数组。

下一行特别复杂。它遍历每对索引,然后从较大的索引中减去较小的索引。如果这是1(并且我们不在最后一对 2上),则在相同的对角线上有两个皇后,并插入值-2,否则将插入字符串中皇后的原始索引。

最后一行总结每个索引的所有索引,并检查它是否是n-1的三角形数字,其中n是正方形的宽度(或高度)。

1:-1是我的首选,但它与0相距1,因此会影响对角线的检查。否定最终结果总和是错误的。我想到了一个很大的数字(只有一位数字),例如9,但是我不确定这不会导致错误的验证。
2:板子不环绕,而ruby的rotate数组函数可以,如果最后一对相差一个,那没关系-这不是对角线。


0

PHP,137个 143字节

尼尔解决方案启发

for($n=1+strlen($s=$argv[1])**.5|0;($c=$s[$p])&&!(Q==$c&&$v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++);$p++);echo$n-1==count($a)&&!$c;

从第一个命令行参数获取输入;与运行-r。需要单字节换行符。
其实你可以使用任何字符0,除了换行符之外,。
打印true(1)或false(空字符串)。

分解

for($n=1+strlen($s=$argv[1])**.5|0; // copy input to $s, $n=size+1 (for the linebreak)
    ($c=$s[$p])&&!(                 // loop through characters
        Q==$c&&                         // if queen: test and increment lines
            $v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++
    );                                  // break if a line had been marked before
    $p++);
echo$n-1==count($a)             // print result: true for $n-1(=size) marks
    &&!$c;                      // and loop has finished

0

Python 3中185 176 175 172 171字节

lambda x,c=lambda x:x.count("Q")==1:all([*map(c,x+[[l[i]for l in x]for i in range(len(x[0]))])])*~any(map(lambda s:"Q%sQ"%(s*".")in"".join(x),[len(x[0]),len(x[0])-2]))==-1

以字符串列表作为输入的匿名函数。

Python 2,175字节

lambda x:all([a.count("Q")==1for a in x]+[[l[i]for l in x].count("Q")==1for i in range(len(x[0]))]+[all(map(lambda s:"Q%sQ"%(s*".")not in"".join(x),[len(x[0]),len(x[0])-2]))])
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.