projecteuler.net 题目笔记 [15]

题目15:从20*20的网格的左上角通往右下角有多少条路?

从一个2×2网格的左上角开始,有6条(不允许往回走)通往右下角的路。

 

projecteuler.net 题目笔记 [15]_第1张图片

对于20×20的网格,这样的路有多少条?

class NetGame():
    """丢入一个n X n格的网络
    说明: x:横坐标, y:纵坐标   如(x,y)表示 数组net[y][x]
    """
    def __init__(self,cell=None):       # 初始化网络 ,从左上角开始,到右下角,只能向右/向下方向前进
        if not cell:raise KeyError
        self.net = [[0 for i in range(cell+1)] for j in range(cell+1)]  # 建立二维坐标网络
        self.length = cell+1            # 长度
    def check_next(self,x,y):
        """检测下一步可以向哪方向走
        {'down':True,'right':False}
        """
        arrow = {'down':True,'right':True}
        if y >= self.length-1:
            arrow['down'] = False
        if x >= self.length-1:
            arrow['right'] = False
        return arrow
    def go_down(self,x,y):
        # 传入向下走一步, 返回坐标
        return (x,y+1)
    def go_right(self,x,y):
        # 向右走一步
        return (x+1,y)
    def check_end(self,x,y):
        """检查坐标是否已经到终点"""
        if (x,y) == (self.length-1, self.length-1):
            return True
        return False
    def run_from_xy(self,x,y ):
        """从当前坐标(x,y) 开始向坐标(n-1,n-1)终点行走,返回可能的路线.
        """
        path_list = [(x,y)]     # 收集途经坐标,第一个是起点坐标
        def running(path_list):
            x,y = path_list[-1]     # 最后一个坐标
            if self.check_end(x,y):
                yield path_list
            arrow = self.check_next(x,y)
            for direction,TF in arrow.iteritems():
                if TF:    # 哪个方向可以走, 设置为1
                    go_func = eval('self.go_%s' % direction)     # 套入go_down,go_right
                    new_x,new_y = go_func(x,y)          # 取得下一步的坐标 在这里 x,y=go_func(x,y) 吃了大亏!!
                    path_list_new = path_list[:]
                    path_list_new.append((new_x,new_y))     # 将坐标加入路径列表
                    for i in running(path_list_new):
                        yield i
        return running(path_list)
    def run(self):
        """从(0,0)坐标开始行走,返回经过坐标的列表"""
        return self.run_from_xy(0,0)
    @property
    def count(self):
        """列出所有路线之和,从(0,0)开始"""
        count_cnt = 0
        for ele in self.run():
            count_cnt += 1
        return count_cnt
    def list_array(self):
        """列出所有线路的二维数组"""
        import copy
        for coordinate in self.run():   # 返回坐标列表
            net = copy.deepcopy(self.net)
            for x,y in coordinate:
                net[y][x] = 1
            yield net

似乎可以做成机器人走走的算法. 



首先验证一下题目

import time
t1 = time.time()
net = NetGame(cell=2)
print "经过的线路坐标:"
cnt = 0
for e in net.run():
    print e
    cnt+=1
print "路线数:",cnt
t2 = time.time()
print "共用时间:",t2-t1

print "所有的线路二维坐标:"
for i in net.list_array():
    print i

经过的线路坐标:

[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)]

[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)]

[(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)]

[(0, 0), (1, 0), (1, 1), (1, 2), (2, 2)]

[(0, 0), (1, 0), (1, 1), (2, 1), (2, 2)]

[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]

路线数: 6

共用时间: 0.0


所有的线路二维坐标:

[[1, 0, 0], [1, 0, 0], [1, 1, 1]]

[[1, 0, 0], [1, 1, 0], [0, 1, 1]]

[[1, 0, 0], [1, 1, 1], [0, 0, 1]]

[[1, 1, 0], [0, 1, 0], [0, 1, 1]]

[[1, 1, 0], [0, 1, 1], [0, 0, 1]]

[[1, 1, 1], [0, 0, 1], [0, 0, 1]]



如果改为10格呢j, 线路列表太多,不输出了.

import time
t1 = time.time()
net = NetGame(cell=10)
print "路线数:",net.count
t2 = time.time()
print "共用时间:",t2-t1

路线数: 184756

共用时间: 10.503000021


如果是20格呢? 所用时间半个小时也运行不完.  算法不太懂. 先略过



贴上一个很吊的算法:

cache = {}
def countRoutes(m,n):
    if m==0 or n==0:
        return 1
    if (m,n) in cache:
        return cache[(m,n)]
    cache[(m,n)] = countRoutes(m,n-1) + countRoutes(m-1,n)
    return cache[(m,n)]
import time
t1 = time.time()
print countRoutes(20,20)
print time.time()-t1

137846528820

0.0

时间为0 !!!!!!


你可能感兴趣的:(projecteuler.net 题目笔记 [15])