网格交叉顺序


17

如果您拿一张方格纸并画一条m向右移动并向n上移动的斜线,则您将按一定顺序交叉n-1水平和m-1垂直网格线。编写代码以输出该序列。

例如,m=5并且n=3给出了:

网格线交叉,m = 5,n = 3

可能相关:产生欧几里德节奏斐波那契平铺FizzBu​​zz

输入:m,n相对质数的两个正整数

输出:将交叉点作为两个不同标记的序列返回或打印。例如,它可以是一串HV的列表,True并且False,或0的和1的打印在单独的行。令牌之间可以有分隔符,只要它始终是相同的即可,而不是可变数量的空格。

测试用例:

第一个测试用例输出为空或不输出。

1 1 
1 2 H
2 1 V
1 3 HH
3 2 VHV
3 5 HVHHVH
5 3 VHVVHV
10 3 VVVHVVVHVVV
4 11 HHVHHHVHHHVHH
19 17 VHVHVHVHVHVHVHVHVVHVHVHVHVHVHVHVHV
39 100 HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHH

格式(m,n,output_as_list_of_0s_and_1s)

(1, 1, [])
(1, 2, [0])
(2, 1, [1])
(1, 3, [0, 0])
(3, 2, [1, 0, 1])
(3, 5, [0, 1, 0, 0, 1, 0])
(5, 3, [1, 0, 1, 1, 0, 1])
(10, 3, [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1])
(4, 11, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0])
(19, 17, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
(39, 100, [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0])

2
今天在PPCG上:布雷森纳姆(Bresenham)高尔夫的线条绘制算法
Sparr

根据您添加的替代格式,是否可以/必须将输入重复作为输出的一部分?否则,我不明白为什么输入和输出是同一列表的一部分。
Reto Koradi

@RetoKoradi不,您不应该包括输入。我将其放在元组中,以使其更易于处理测试用例。
xnor

我可以预见答案,但问一下就不会受伤:使用空格字符作为输出标记之一是否可以接受?结果将是输出中可能存在大量的前导/后继空间。不会有其他空格,因此所有空格都是有意义的。
Reto Koradi

@RetoKoradi不,因为尾部空格不可见。
xnor

Answers:


7

Ruby,92岁;鸵鸟0.7.0,38

f=->m,n{((1..m-1).map{|x|[x,1]}+(1..n-1).map{|x|[1.0*x*m/n,0]}).sort_by(&:first).map &:last}
:n;:m1-,{)o2W}%n1-,{)m n/*0pW}%+_H$_T%

它们的输出都使用1和0(例如101101)。


这是鸵鸟的一种解释:

:n;:m    store n and m as variables, keep m on the stack
1-,      from ex. 5, generate [0 1 2 3]
{...}%   map...
  )        increment, now 5 -> [1 2 3 4]
  o        push 1 (the digit 1 is special-cased as `o')
  2W       wrap the top two stack elements into an array
           we now have [[1 1] [2 1] [3 1] [4 1]]
n1-,     doing the same thing with n
{...}%   map...
  )        increment, now 3 -> [1 2]
  m n/*    multiply by slope to get the x-value for a certain y-value
  0        push 0
  pW       wrap the top two stack elements (2 is special-cased as `p')
+        concatenate the two arrays
_H$      sort-by first element (head)
_T%      map to last element (tail)

并以Ruby代码为指导,对整个过程进行了解释:

f = ->m,n {
    # general outline:
    # 1. collect a list of the x-coordinates of all the crossings
    # 2. sort this list by x-coordinate
    # 3. transform each coordinate into a 1 or 0 (V or H)
    # observation: there are (m-1) vertical crossings, and (n-1) horizontal
    #   crossings. the vertical ones lie on integer x-values, and the
    #   horizontal on integer y-values
    # collect array (1)
    (
        # horizontal
        (1..m-1).map{|x| [x, 1] } +
        # vertical
        (1..n-1).map{|x| [1.0 * x * m/n, 0] }  # multiply by slope to turn
                                               # y-value into x-value
    )
    .sort_by(&:first)  # sort by x-coordinate (2)
    .map &:last        # transform into 1's and 0's (3)
}

5

Python,53岁

这使用True / False列表输出。这里没什么特别的。

lambda m,n:[x%m<1for x in range(1,m*n)if x%m*(x%n)<1]

4

Pyth- 32 24字节

Jmm,chk@Qddt@Qd2eMS+hJeJ

通过stdin以格式输入[m,n]。将结果作为0和1的列表输出到stdout,其中0 = V和1 =H。

在线测试


说明:

J                           # J = 
 m             2            # map(lambda d: ..., range(2))
  m        t@Qd             # map(lambda k: ..., range(input[d] - 1))
   ,chk@Qdd                 # [(k + 1) / input[d], d]
                eMS+hJeJ    # print map(lambda x: x[-1], sorted(J[0] + J[-1])))

您可以在映射结束时使用语法映射运算符来保存字节。eM与相同med
Maltysen

另外,@"VH"由于允许打印,所以您可以取出01代替VH
Maltysen

您可以使用内联分配来保存另一个字节J。这是我到目前为止有25个字节的内容:pyth.herokuapp.com/…–
Maltysen

@Maltysen,谢谢,我想您可以将其删除,jk因为输出可以是列表。
蒂洛2015年

您可以在我对内联分配的评论中查看23条。
Maltysen

4

IA-32机器代码,26个字节

代码的十六进制转储:

60 8b 7c 24 24 8d 34 11 33 c0 2b d1 74 08 73 03
03 d6 40 aa eb f2 61 c2 04 00

我从以下C代码开始:

void doit(int m, int n, uint8_t* out)
{
    int t = m;
    while (true)
    {
        if (t >= n)
        {
            t -= n;
            *out++ = 1;
        }
        else
        {
            t += m;
            *out++ = 0;
        }
        if (t == n)
            break;
    }
}

它将输出写入提供的缓冲区。它不会返回输出的长度,但并不是真正需要的:输出长度始终为m + n - 2

int main()
{
    char out[100];
    int m = 10;
    int n = 3;
    doit(m, n, out);
    for (int i = 0; i < m + n - 2; ++i)
    {
        printf("%d ", out[i]);
    }
}

要将C代码转换为机器代码,我首先进行了一些调整,以使其中一个if/else分支为空,然后与0而不是进行比较n

void doit(int m, int n, char* out)
{
    int t = n;
    while (true)
    {
        int r = 0;
        t -= m;
        if (t == 0)
            break;
        if (t >= 0)
        {
        }
        else
        {
            t += m + n;
            ++r;
        }
        *out++ = r;
    }
}

从这里开始,编写内联汇编代码非常简单:

__declspec(naked) void __fastcall doit(int x, int y, char* out)
{
    _asm
    {
        pushad;                 // save all registers
        mov edi, [esp + 0x24];  // edi is the output address
        lea esi, [ecx + edx];   // esi is the sum m+n
    myloop:                     // edx is the working value (t)
        xor eax, eax;           // eax is the value to write (r)
        sub edx, ecx;
        jz myout;
        jae mywrite;
        add edx, esi;
        inc eax;
    mywrite:
        stosb;                  // write one value to the output
        jmp myloop;
    myout:
        popad;                  // restore all registers
        ret 4;                  // return (discarding 1 parameter on stack)
    }
}

我很好奇-为什么此算法有效?
xnor

@xnor非正式地,它跟踪fizzbuzz序列。这t是“到buzz”的距离。如果距离至少是n,走fizz,否则走buzz; 更新距离;重复直到它为
0。– anatolyg

3

Python-125个字节

使用非常简单的算法,仅增加坐标并检测其越线并打印出来。希望翻译成Pyth。

a,b=input()
i=1e-4
x=y=l=o=p=0
k=""
while len(k)<a+b-2:x+=i*a;y+=i*b;k+="V"*int(x//1-o//1)+"H"*int(y//1-p//1);o,p=x,y
print k

while循环正在检查lines 的数量,然后通过减去来检查是否有任何值超出int边界。

39, 100stdin 一样接受输入,并像HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHstdout 一样打印输出。


3

CJam,15个字节

Ll~_:*,\ff{%!^}

在这里尝试。

01为V和10H 打印。

说明

L          e# An empty list.
l~         e# Evaluate the input.
_:*,       e# [0, m*n).
\          e# The input (m and n).
ff{%!      e# Test if each number in [0, m*n) is divisible by m and n.
^}         e# If divisible by m, add an 10, or if divisible by n, add an 01 into
           e# the previous list. If divisible by neither, the two 0s cancel out.
           e# It's just for output. So we don't care about what the previous list
           e# is -- as long as it contains neither 0 or 1.

对角线在整个对角线的每1 / n处横越一条水平线,在每1 / m越过一条垂直线。


您会为此添加解释吗?这很有意思,但是至少从最初的快速观察来看,我不明白它为什么起作用。通过使用它,我注意到它仅适用于相对质数的值(在问题描述中给出),而我的适用于所有值。因此,基础数学显然有很大不同。
Reto Koradi 2015年

在让它沉入更多之后,我相信我至少了解算法部分。以后必须研究输出生成逻辑。
Reto Koradi 2015年

@RetoKoradi编辑。
jimmy23013 2015年

2

TI-BASIC,32岁

Prompt M,N
For(X,1,MN-1
gcd(X,MN
If log(Ans
Disp N=Ans
End

直截了当。使用的序列01,由换行分离。TI-BASIC的优点是2字节gcd(隐式乘法,但缺点是For循环(包括结束值)和5字节的输入开销。



1

Haskell,78个字节

import Data.List
m#n=map snd$sort$[(x,0)|x<-[1..m-1]]++[(y*m/n,1)|y<-[1..n-1]]

用法示例:

*Main> 19 # 17
[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
*Main> 10 # 3
[0,0,0,1,0,0,0,1,0,0,0]

工作原理:(x,0)x[1,2,...,m-1]中的所有垂直交叉点0的x值列表(表示垂直),并(y*m/n,1)yin 附加所有水平交叉点的x值列表[1,2,...,n-1](1表示水平)。排序并取对中的第二个元素。

今日的诅咒:同样,我不得不在上花费17个字节,import因为sort它在Data.List标准库中,而不是在标准库中。


1

KDB(Q),44个字节

{"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}

说明

找到相交点的所有x轴值并将其排序。如果mod 1为零,则其“ V”为非零,即为“ H”。

测试

q){"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}[5;3]
"VHVVHV"

1

CJam,26个 24字节

l~:N;:M{TN+Mmd:T;0a*1}*>

在线尝试

非常简单,几乎是Bresenham类型算法的直接实现。

说明:

l~    Get input and convert to 2 integers.
:N;   Store away N in variable, and pop from stack.
:M    Store away M in variable.
{     Loop M times.
  T     T is the pending remainder.
  N+    Add N to pending remainder.
  M     Push M.
  md    Calculate div and mod.
  :T;   Store away mod in T, and pop it from stack
  0a    Wrap 0 in array so that it is replicated by *, not multiplied.
  *     Emit div 0s...
  1     ... and a 1.
}*      End of loop over M.
>       Pop the last 1 and 0.

最后一个01需要弹出,因为循环一直到终点,这不是他想要的输出的一部分。请注意,我们不能简单地将循环数减少1。否则,因为最后一次迭代的N > M所有0s都将丢失,而我们只需要去除最后一次0


1
你可以使用>;W<
jimmy23013 2015年

@ jimmy23013好主意。因为我知道我1在堆栈的顶部,所以我最好还是有效率地使用它。
Reto Koradi 2015年
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.