给我缠绕一些蛇!


34

给定一个输入整数n,绘制一条数字蛇,即一个n x n由数字组成的网格,该数字1通过n^2以下方式相互缠绕:

输入n = 3

7 8 9
6 1 2
5 4 3

输入n = 4

 7  8  9 10
 6  1  2 11
 5  4  3 12
16 15 14 13

输入n = 5

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13

(受此问题启发从项目欧拉)。

这是,最短的答案以字节为单位!


4
例如:4?或任何偶数。
TheLethalCoder

1
我们可以假设输入是奇数吗?
Xcoder先生17年



1
另请参见perlmonks.com/?node_id=487200,其中包含许多解决方案和答复链接。
b_jonas

Answers:



18

C#,203个 202 196 193 178字节

n=>{var r=new int[n,n];for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,b=1-2*(i%2),j;n>i++;){r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;}return r;}

感谢@StefanDelport,节省了一个字节。
感谢@FelipeNardiBatista,节省了22个字节。

通过观察正方形的构建方式,可以达到以下目的:

Image of square where n=5

如您所见,每个位都添加到上一个正方形上。对于偶数,我们从我们所在的位置开始,向下直到比正方形所在的位置低一个,然后移到最后。奇数实际上是相反的,我们左移一个,直到高出当前高度一个,然后再右移到底。

完整/格式化版本:

using System;
using System.Linq;

class P
{
    static void Main()
    {
        Func<int, int[,]> f = n =>
        {
            var r = new int[n, n];
            for (int o = n - 2 + n % 2 >> 1, i = r[o, o] = 1, c = 2, w = o, h = o, b = 1 - 2 * (i % 2), j; n > i++;)
            {
                r[h, w += b] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h += b, w] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h, w -= b] = c++;
            }

            return r;
        };

        Console.WriteLine(String.Join("\n", f(3).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(4).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(5).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");

        Console.ReadLine();
    }
}

public static class ArrayExtensions
{
    public static T[][] ToJagged<T>(this T[,] value)
    {
        T[][] result = new T[value.GetLength(0)][];

        for (int i = 0; i < value.GetLength(0); ++i)
            result[i] = new T[value.GetLength(1)];

        for (int i = 0; i < value.GetLength(0); ++i)
            for (int j = 0; j < value.GetLength(1); ++j)
                result[i][j] = value[i, j];

        return result;
    }
}

1
++i<=n;可以变成n>++i+1。
LiefdeWen

1
n%2<1?2:12-x%2?我尚未在C#中对其进行测试,但是在C和Python中它确实有效。
Felipe Nardi Batista

1
for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,j;n>i++;){var b=i%2<1; ....打了一下高尔夫球
Felipe Nardi Batista

@FelipeNardiBatista太棒了,永远都不会想到这两个!谢谢。
TheLethalCoder

1
var b=1-2*(i%2);r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;
菲利佩·纳尔迪·巴蒂斯塔

15

Dyalog APL,70 56 45 41字节

,⍨⍴∘(⍋+\)×⍨↑(⌈2÷⍨×⍨),(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

在线尝试!

怎么样?

(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

计算指标之间的差异;1¯1对于左,右,¯⍵以及为上下。

1,⊢,¯1,-的出现是1 ⍵ ¯1 ¯⍵,将+⍨⍴这个数组延伸到的长度⍵×2,因此final 2/⍳可以重复其中的每个元素,重复计数每第二个元素增加一次:

      (1,⊢,¯1,-) 4
1 4 ¯1 ¯4
      (+⍨⍴1,⊢,¯1,-) 4
1 4 ¯1 ¯4 1 4 ¯1 ¯4
      (2/⍳) 4
1 1 2 2 3 3 4 4
      ((+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳) 4
1 4 ¯1 ¯1 ¯4 ¯4 1 1 1 4 4 4 ¯1 ¯1 ¯1 ¯1 ¯4 ¯4 ¯4 ¯4

然后,

(⌈2÷⍨×⍨),

在螺旋的左上方

×⍨↑

限制此距离列表的前⍵2 元素,

+\

执行累计和,

对索引(⍵[i] = ⍵[⍵[i]])进行分级,以将原始矩阵与每个元素的索引进行平移,最后

,⍨⍴

形状作为⍵×⍵矩阵。


对于那些感兴趣的人,这篇优秀的文章详细讨论了这种技术。
约拿(

9

C,321个 307 295 284 283 282字节

感谢@Zachary T和@Jonathan Frech打高尔夫球!

#define F for(b=a;b--;)l
i,j,k,a,b,m;**l;f(n){n*=n;l=calloc(a=m=3*n,4);F[b]=calloc(m,4);for(l[i=j=n][j]=a=k=1;n>k;++a){F[i][++j]=++k;F[++i][j]=++k;++a;F[i][--j]=++k;F[--i][j]=++k;}for(i=0;i<m;++i,k&&puts(""))for(j=k=0;j<m;)(a=l[i][j++])>0&&a<=n&&printf("%*d ",(int)log10(n)+1,k=a);}

分配零的二维数组,然后从中间的某个位置开始填充它。最后,打印出大于零但小于或等于输入平方的值。

在线尝试!

格式:

#define F for(b=a; b--;)l
i, j, k, a, b, m; **l;
f(n)
{
    n *= n;
    l = calloc(a=m=3*n, 4);

    F[b] = calloc(m, 4);

    for(l[i=j=n][j]=a=k=1; n>k; ++a)
    {
        F[i][++j] = ++k;
        F[++i][j] = ++k;
        ++a;

        F[i][--j] = ++k;
        F[--i][j] = ++k;
    }

    for(i=0; i<m; ++i, k&&puts(""))
        for(j=k=0; j<m;)
            (a=l[i][j++])>0 && a<=n && printf("%*d ", (int)log10(n)+1, k=a);
}

1
是否有可能取代i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4);i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4);保存字节?
扎卡里

1
您可以替换k<=n;n>k;保存字节。
乔纳森·弗雷希

6

PHP,192字节

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=$a/2^$w=0;$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$e[$x-!($a&1)][$y]=sprintf("%$l".d,$i);for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);

在线尝试!

用相同的方法构建字符串而不是数组

PHP,217字节

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=($a/2^$w=0)-!($a&1),$s=str_pad(_,$q*$l);$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$s=substr_replace($s,sprintf("%$l".d,$i),($x*$a+$y)*$l,$l);echo chunk_split($s,$a*$l);

在线尝试!


1
[-1,1][$d&1]->$d&1?:-1
泰特斯(Titus),

@Titus谢谢我还没有看到它
约尔格Hülsermann

1
这是另外一个字节:for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);。而另一个问题:"%$l".d。还有一个:$x*$l*$a+$y*$l-> ($x*$a+$y)*$l
泰特斯(Titus),

1
我认为在第二个版本中,您可以初始化$s为带下划线的下划线(或字母或数字)。该字符将被覆盖。
泰特斯(Titus),

@Titus谢谢你,你可以用.d你自己的方式来节省2个字节
约尔格Hülsermann

6

PHP,185个176 174字节

for(;$n++<$argn**2;${xy[$m&1]}+=$m&2?-1:1,$k++<$p?:$p+=$m++%2+$k=0)$r[+$y][+$x]=$n;ksort($r);foreach($r as$o){ksort($o);foreach($o as$i)printf(" %".strlen($n).d,$i);echo"
";}

使用-nR或以管道方式运行在线测试

分解

for(;$n++<$argn**2;     # loop $n from 1 to N squared
    ${xy[$m&1]}+=$m&2?-1:1, # 2. move cursor
    $k++<$p?:               # 3. if $p+1 numbers have been printed in that direction:
        $p+=$m++%2+             # increment direction $m, every two directions increment $p
        $k=0                    # reset $k
)$r[+$y][+$x]=$n;           # 1. paint current number at current coordinates

ksort($r);              # sort grid by indexes
foreach($r as$o){       # and loop through it
    ksort($o);              # sort row by indexes
    foreach($o as$i)        # and loop through it
        printf(" %".strlen($n).d,$i);   # print formatted number
    echo"\n";               # print newline
}

6

APL(Dyalog Classic)32 29字节

1+×⍨-{⊖∘⌽⍣⍵⌽{⌽⍉,⌸⍵+≢⍵}⍣2⍣⍵⍪⍬}

在线尝试!

用途⎕io←1。以0×1矩阵(⍪⍬)开头。2N次(⍣2⍣⍵)将矩阵(≢⍵)的高度添加到其每个元素,放到1 2...height其右侧(,⌸),然后旋转(⌽⍉)。完成后,请更正结果(⊖∘⌽⍣⍵⌽)的方向,并通过从N 2 +1(1+×⍨-)中减去它们来反转数字。


5

Mathematica,177个字节

(n=#;i=j=Floor[(n+1)/2];c=1;d=0;v={{1,0},{0,-1},{-1,0},{0,1}};a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]], {k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];Grid@a)&

8
Waaait,Mathematica中没有内置功能吗?
Xcoder先生17年

5

C ++,245228字节

void f(){for(int i=0,j=-1,v,x,y,a,b;i<n;i++,j=-1,cout<<endl)while(++j<n){x=(a=n%2)?j:n-j-1;y=a?i:n-i-1;v=(b=y<n-x)?n-1-2*(x<y?x:y):2*(x>y?x:y)-n;v=v*v+(b?n-y-(y>x?x:y*2-x):y+1-n+(x>y?x:2*y-x));cout<<setw(log10(n*n)+1)<<v<<' ';}}

在线尝试!

该函数通过应用以下逻辑根据矩阵的x,y位置计算并打印矩阵每个数字的值:

Snake values calculation depending on position

格式化版本

#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

void f(int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int value = 0;

            // Invert x and y when n is even
            int x = n % 2 == 0 ? n - j - 1 : j;
            int y = n % 2 == 0 ? n - i - 1 : i;
            if (y < (n - x))
            {
                // Left-top part of the matrix
                int padding = x < y ? x : y;
                value = n - 1 - padding * 2;
                value *= value;
                value += y >= x ? n - x - y : n + x - y - (y * 2);
            }
            else
            {
                // Right-bottom part of the matrix
                int padding = x > y ? n - x : n - y;
                value = n - padding * 2;
                value *= value;
                value += x > y ? y - padding + 1 : n + y - x - (padding * 2) + 1;
            }

            cout << setw(log10(n * n) + 1);
            cout << value << ' ';
        }

        cout << endl;
    }
}

int main()
{
    int n;
    while (cin >> n && n > 0)
    {
        f(n);
        cout << endl;
    }
}

5

Python 3中249 247字节

我初始化一个2D数组并找到起点,它是奇数n的中心或偶数n的偏移量(-1,-1)的中心,然后使用当前的“环”号缩放填充/光标模式。我觉得我缺少解释方向的窍门,但我没有想出任何便宜的东西。

def f(n):
 M=[n*[0]for a in range(n)]
 x=y=n//2-1+n%2
 M[x][y]=i=s=1
 while 1:
  t=s*2
  for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t:
   if i==n*n:print(*M,sep='\n');return
   v=[1,-1][d in'LU']
   if d in'UD':x+=v
   else:y+=v
   M[x][y]=i=i+1
  s+=1

在线尝试!

-2感谢Zachary T!


您如何计算字节数?标签,空格和换行符也很重要
Felipe Nardi Batista

我用\“ \ n和\ t替换了\ n和\ t并加上了len()。我只是复制了上面的内容并进行了重新命名,以确保我没有进行任何更改并忘记了重新计数,但是我得到了相同的数字。我错过了什么?
nocturama

我正在计数\t\n作为1个字节,仍然有249个字节
Felipe Nardi Batista

e:^^^我应该使用更好/更简便的方法吗?^^^奇怪,这就是我在IDLE中遇到的问题:len("def f(n): M=[n*[0]for a in range(n)] x=y=n//2-(n%2<1) M[x][y]=i=s=1 while 1: t=s*2 for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t: if i==n*n:print(*M,sep='\n');return v=[1,-1][d in'LU'] if d in'UD':x+=v else:y+=v M[x][y]=i=i+1 s+=1") 223
nocturama

通常,文本编辑器会告诉您选择了多少个字符,因此按CTRL + A并阅读其内容
Felipe Nardi Batista

5

Wolfram语言(Mathematica)(...) 83字节

以UTF8为单位的字节,\[LeftFloor])和\[RightFloor])各自花费3个字节。Mathematica没有任何特殊的字节字符集。

Table[Max[4x^2-Max[x+y,3x-y],4y
y-{x+y,3y-x}]+1,{y,b+1-#,b=⌊#/2⌋},{x,b+1-#,b}]&

在线尝试!


对这4种情况分别使用封闭形式,然后仔细取最大值以得到所需的结果。

返回一个二维整数数组。我不确定是否允许这样做,尽管评论中已要求这样做,但OP没有回复。


4

Clojure,206字节

(defmacro F[s]`(if(~'r(+ ~'p ~'v ~s))~'v ~s))
#(loop[i 1 p(*(quot(dec %)2)(inc %))v 1 r{}](if(<(* % %)i)(partition %(map r(range i)))(recur(inc i)(+ p v)({1(F %)-1(F(- %))%(F -1)(- %)(F 1)}v)(assoc r p i))))

我想这是一个不错的开始,将板按顺序构建为哈希图,然后将其划分为n x n列表。那defmacro结束了很长,但代码与它比没有更短。有没有更简洁的语法来描述它?

大量字节计算起点,并建立下一个速度的查找逻辑v。也许嵌套vec会更好,但是随后您需要跟踪两个索引和速度。


3

J,41个字节

(]|.@|:@[&0](|.@|:@,.*/@$+#\)@]^:[1:)2*<:

在线尝试!

做与ngn的APL提交相同的操作,但从1乘1矩阵开始,并重复2×N-2次。


您能改善我的替代方法(现在排名41)打败自己吗?到目前为止,我已经给了我最好的高尔夫机会,但是我怀疑至少可以再剃掉几个字节。
约拿书

1

Python 165(或144)

from pylab import *
def S(n):
 a=r_[[[1]]];r=rot90;i=2
 while any(array(a.shape)<n):
  q=a.shape[0];a=vstack([range(i,i+q),r(a)]);i+=q
 if n%2==0:a=r(r(a))
 print(a)

这将创建一个numpy数组,然后旋转它并添加一面直到达到正确的大小。问题没有指定是否需要对偶数和奇数使用相同的起点,如果不是这样,if n%2==0:a=r(r(a))可以删除该行,节省21个字节。


1
这不是Python,而是Python + numpy
仅限ASCII

@仅ASCII某处是否存在可接受的语言名称的主列表?这是完全有效的python。
user2699

它使用一个库,所以你需要包括库的名称,以及...为允许语言,用公开可用的实施方案的任何语言,你可以去运行,允许
ASCII-仅

@ASCII仅写在哪里?我还没有看到大多数python答案都能做到这一点。
user2699

是的,因为它们中的大多数不使用numpy ...并且stdlib不算作外部库
仅ASCII的

0

J,41个字节

,~$[:/:[:+/\_1|.1&,(]##@]$[,-@[)2}:@#1+i.

标准格式

,~ $ [: /: [: +/\ _1 |. 1&, (] # #@] $ [ , -@[) 2 }:@# 1 + i.

这种方法基于“ J弹奏比赛”(Uriel的APL使用类似的技术)。

我想这是出乎意料且优雅的,足以证明第二个J答案的合理性。

本质上,我们不执行任何程序性甚至几何性的操作。取而代之的是,我们算术上创建了一个简单的序列,当对扫描进行求和并累加时,将给出螺旋数从左到右,从上到下的正确顺序。然后,我们将其成形为矩阵并完成。

如果时间允许,我将添加更详细的解释,但是链接的文章对此进行了深入的解释。

在线尝试!


0

Python 3中(无堆栈)192个 188 179 150字节

lambda n:[list(map(v,list(range(t-n,t)),[y]*n))for t in[1+n//2]for y in range(n-t,-t,-1)]
v=lambda x,y,r=0:y>=abs(x)and(3-2*r+4*y)*y+x+1or v(y,-x,r+1)

在线尝试!

这里的算法是为网格中的每个坐标形成一个相量,然后将其顺时针旋转90度,直到相量位于上对角线之间。可以使用一个简单的公式基于坐标和顺时针旋转数来计算值:

2ÿ+1个2-ÿ-X-2ÿ[R

由于90度相量旋转无需复数即可轻松完成,因此节省了4个字节


0

R,183字节

x=scan()
b=t(d<-1)
while(2*x-1-d){m=max(b)
y=(m+1):(m+sum(1:dim(b)[2]|1))
z=d%%4
if(z==1)b=cbind(b,y)
if(z==2)b=rbind(b,rev(y))
if(z==3)b=cbind(rev(y),b)
if(z==0)b=rbind(y,b)
d=d+1}
b

在线尝试!

输出是矩阵蛇(或蛇矩阵,无论如何)。这可能不是最有效的方法,并且可能打了高尔夫球,但我认为值得一试。我为此感到非常自豪!

该方法从内到外构建矩阵,始终在附加之前附加等于矩阵中列数的整数。接下来的模式是按列或按行绑定,同时还反转了一些值,以便按正确的顺序附加它们。

193字节

与上述完全相同,但最后一个b

matrix(b,x)

在线尝试!

这样输出的内容会更干净一些,但是我没有看到任何特殊的输出标准,因此,如果我没有记错的话,第一个答案应该有效。

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.