网格路径问题

2013-09-07

题目是这样的:

Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.

How many such routes are there through a 20×20 grid?

这个题来自 Project Euler第 15 题。翻译为中文的话,题意大致是:

从一个 2x2 的网络的左上角出发,只能向右或向下移动,到右下角一共有 6 种不同的走法。那么,对一个 20x20 的网络来说,有多少种不同的走法呢?

我们来绘制一个大一些的网格,并将它的横向记为 X 坐标,纵向记为 Y 坐标,每个交点依次编号,如下图:

这样,我们都可以使用形如 (x, y) 这样的坐标来表示网格中的每一个交点了,比如下图中的黑点位置可以用坐标 (4, 3) 来表示。

可以发现,如果从左上角即坐标 (0, 0) 处出发,只能向右或向下移动,到达接下来几个交点的走法类似下图所示:

每个交点右下方的蓝色数字表示从左上角出发到达这个位置的不同走法,例如坐标 (2, 2) 右下角的数字是 6 ,即到达这个位置共有 6 种不同的走法。这也即原题中 2x2 的格子的不同走法。

观察这个网格,可以发现除了最上边及最左边的交点外,各个交点的走法等于它上方及左方交点走法的和。

如上图所示,坐标 (4, 3) 处的走法共有 35 种,等于它上方的网格 (4, 2) 的走法(15 种)加上它左方的网格 (3, 3) 的走法(20 种)之和。

也就是说,如果用函数 r(x, y) 来表示到达坐标 (x, y) 的走法,我们可以总结出下面的公式:

根据上面的公式,我们很容易编写出对应的代码来,以 Python 为例:

def r(x, y):
    if x == 0 and y == 0:
        p = 0
    elif x == 0 or y == 0:
        p = 1
    else:
        p = r(x - 1, y) + r(x, y - 1)

    return p

不过,需要注意的是,上面的代码用到了递归,当 x、y 的值变大时,递归的次数以指数级别上升,因此,要计算 r(20, 20) ,用这个方法效率是非常低的。我们可以再将程序改进一下,像下面这样:

def r(x, y):
    d = []
    for i in range(y + 1):
        t = [0] * (x + 1)
        d.append(t)

    for iy in range(y + 1):
        for ix in range(x + 1):
            if ix == 0 and iy == 0:
                v = 0
            elif ix == 0 or iy == 0:
                v = 1
            else:
                v = d[iy - 1][ix] + d[iy][ix - 1]
            d[iy][ix] = v

    return d[y][x]

这样便快很多了,很容易计算出,r(20, 20) 的值为 137846528820,也即对一个 20x20 的网格来说,从左上角走到右下角,一共有 137846528820 种不同的走法。

至此,这题便解答完成了,在 Project Euler 的论坛上还有很多种其他解法。另外,观察这个网格,每个交点处的值都是它上方及左方两个交点的值的和,这一点有点像斐波那契数列,不过形式上是二维的。

分类:编程标签:数学
前一篇如何判断用户是否访问过某个网址
后一篇关于乱停车的概率题

相关文章:

评论:

MatheMatrix
在 2013-09-07 08:20 写道:
老杰……咱俩博客主题居然是一个……你刚换主题了?……
回复
oldj
在 2013-09-07 08:38 写道:
哈哈,是刚换,感觉这个主题比自带的好看多了。:D
回复
wenlong
在 2013-09-07 13:44 写道:
不懂python, 问下改进版的第2,4行表示什么意思?
回复
oldj
在 2013-09-07 14:34 写道:
第2~5行是为了生成一个宽度为 x+1,高度为 y+1 的二维数组,用来表示那个网格。

其中第2行是定义一个新的空数组,第4行是为这个数组追加一行内容(一个长度为 x+1 ,值全为 0 的一维数组)。
回复
苏岳宁
在 2013-09-17 10:04 写道:
老杰,你好。请教一下,你现在使用的主题怎么让首页和归档也显示摘要的呢?
回复
oldj
在 2013-09-22 07:28 写道:
这个主题有这个选项啊,在 外观 -> Contango Theme Settings -> Posts settings 里,Post Style 一项选 Excerpt 就可以了。
回复
北京设计公司
在 2013-09-29 10:24 写道:
有点深度,得慢慢消化
回复
依云
在 2013-10-06 07:01 写道:
对于 m×n 的格子,答案是 (m+n)! / m!n! 好像?
回复
依云
在 2013-10-06 07:09 写道:
啊,进论坛看了,就是40选20啊,第一页最后一个 post……
回复
Leo
在 2015-06-26 10:37 写道:
杨辉三角
回复
oldj
在 2015-06-26 10:50 写道:
犀利~
回复
yyandy
在 2021-09-24 14:16 写道:
其实可以快速求的,O(n)预处理,log(n)求单点的值(取模)。
回复

发表评论:

电子邮件地址不会被公开。必填项已用 * 标注。
0 / 2048