用什么数学理论来解决这个问题?

时间:2016-08-30 16:48:36

标签: java algorithm

我注册了一些在线代码竞赛,其中一个问题是你在一定的k转之后计算一个点在x,y范围内的一个点的位置。我能够通过一个while循环和4个条件语句进行K迭代来解决这个问题,并且它在一定程度上起作用。我总是会在他们的一个“隐藏测试”中受到时间限制。

让我谈谈这个问题,我正在查看其他人的代码并注意到这个很酷的预测算法有效,而不是O(k * n),但基本上是O(2 * n)(n =语句数量)在循环中,k =步数)。有人可以解释他正在使用的数学理论吗?

EDGAR_G6的解决方案:

int[] chessBishopDream(int[] s, int[] xy, int[] dir, int k) {
int k1;
for (int i = 0; i< 2; i++) {        
    if (dir[i] > 0)
        k1 = k - 2*s[i] + xy[i];
    else 
        k1 = k - (xy[i] + 1);
    k1 = k1 % (2*s[i]);
    xy[i] = k1 % s[i];
    System.out.println(xy[i]);
    System.out.println(k1);
    if (k1 >= s[i])
        xy[i] = k1 - 2 * xy[i] - 1;
    xy[i] %= s[i];
}
return xy;
}

以下是问题:question on code fights

谢谢!

直接来自上面的链接就是问题所在:

在ChessLand中,有一位小而自豪的国际象棋主教带着一个反复出现的梦想。在梦中,主教发现自己身处一个n×m的棋盘上,每个边缘都有镜子,它不是一个主教,而是一道光线。这条光线只沿着对角线移动(主教即使在梦中也无法想象任何其他类型的移动),它永远不会停止,一旦它到达棋盘的边缘或角落,它就会从它反射并继续前进。

给定光线的初始位置和方向,在k步之后找到它的位置,其中一步意味着从一个单元移动到相邻单元或从板的一角反射。

实施例

For boardSize = [3, 7], initPosition = [1, 2],
initDirection = [-1, 1] and k = 13, the output should be
chessBishopDream(boardSize, initPosition, initDirection, k) = [0, 1].

这是主教的道路:

[1, 2] -> [0, 3] -(reflection from the top edge)-> [0, 4] -> 
[1, 5] -> [2, 6] -(reflection from the bottom right corner)-> [2, 6] ->
[1, 5] -> [0, 4] -(reflection from the top edge)-> [0, 3] ->
[1, 2] -> [2, 1] -(reflection from the bottom edge)-> [2, 0] -(reflection from the left edge)->
[1, 0] -> [0, 1]

2 个答案:

答案 0 :(得分:5)

我用JavaScript编写了一个解决方案,我将尝试描述我的方法。

首先,我“手动”沿着一个维度走过一系列位置。

例如,在宽度为3且高度为1的棋盘上,如果主教从方形0开始并向正方向移动,则其位置遵循以下模式:

0 1 2 2 1 0 0 1 2 2 1 0 0 1 ...

请注意,图案在6之后重复。另请注意(自己尝试),即使高度大于1,此图案也会保持不变。基本上,您一次只能考虑一个维度。

所以现在,对于我描述的起始条件,我可以告诉你任何k的最终位置:

positions = [0, 1, 2, 2, 1, 0]
final = positions[k % 6]

我们是如何获得positions的?我们通过人工观察做到了,但我们应该能够提出一个公式。因为数字上升然后再次下降,我认为计算该值的一个好方法是使用距离中心的距离(在我们的0到5的范围内为2.5)。如果我们取2.5 - n的绝对值,我们得到这个:

2.5, 1.5, 0.5, 0.5, 1.5, 2.5

2.5减去我们的信息:

0, 1, 2, 2, 1, 0

这正是我们想要的。

一点点思考和试验应该表明,同样的事情在负面方向和任何起始位置都有效。对于3号,我们可以使用:

modulus = 6
middle = 2.5
newPosition = middle - abs(middle - (position + (k * direction)) % modulus)

推广到任何尺寸:

modulus = size * 2
middle = (modulus - 1) / 2

此时,我们可以在恒定时间内解决任何k的问题:

function chessBishopDream(boardSize, initPosition, initDirection, k) {
    // this array will hold the two coordinates of the final position
    var finalPosition = [];

    // first coordinate, second coordinate
    for (var i = 0; i < 2; i++) {
        var position = initPosition[i];
        var direction = initDirection[i];

        // simple addition, ignoring the edges
        var newPosition = position + direction * k;

        // period of the repeating pattern (e.g. 0 1 2 2 1 0 0 1 ...)
        var modulus = boardSize[i] * 2;

        // this is our "index" into the pattern
        newPosition %= modulus;

        // ensure a positive result of the modulo
        if (newPosition < 0) {
            newPosition += modulus;
        }

        var middle = (modulus - 1) / 2;

        finalPosition[i] = middle - Math.abs(middle - newPosition);
    }

    return finalPosition;
}

答案 1 :(得分:1)

看起来这个解决方案使用观察结果x和y部分的位置独立地以相同的速度变化。

相同的速度意味着在k移动后每个坐标将改变k次。独立地表示可以在不知道y坐标的情况下计算x坐标的变化。

很难遵循实际计算,但它有这些步骤

  • 移至扩展板2*s[i]
  • 的边缘
  • k1 % (2*s[i])计算所有反射后的坐标
  • 将结果归一化回正常板