鱼C论坛

 找回密码
 立即注册
查看: 3701|回复: 14

[技术交流] 小练习:20160516 从20*20的网格的左上角通往右下角有多少条路?

[复制链接]
发表于 2016-5-16 10:00:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 冬雪雪冬 于 2016-5-23 10:00 编辑

从现在开始我们要开展一批欧拉计划的习题练习。
其实在我们论坛中已有欧拉计划的板块,可能有些鱼油还没注意到。
什么是欧拉计划:http://bbs.fishc.com/thread-60405-1-1.html
我们欧拉板块现已给出了81道题,这批练习将从欧拉计划中选题。其实用python语言完成有很多的优势,可以更简洁更方便的实现。
如果大家有兴趣也可浏览欧拉的英文网站:https://projecteuler.net/archives
这里已经有了500余题,并且你每做对一题,就可以下载到参考答案的pdf文件,看看你的实现方法与参考答案有什么不同,以利于迅速提高自己的水平。


                               
登录/注册后可看大图

好了言归正传,我们开始做小练习。




题目要求:
以python语言完成,如果是python2请注明。
程序以代码文字格式发帖。
题目比较简单,注重程序效率和创意。
答题在一周内完成,即5.23 10:00之前,其后将公开大家的答案,并评比成绩。

另程序和答案可以在网上搜到,希望大家独立完成。


题目:

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


                               
登录/注册后可看大图


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


本题重要的是找出规律,大家可以先在纸上画画。

奖励:
对所有完成程序并得出正确答案的将给予加分奖励,优秀的将额外加分。
在完成一批题目后,将根据每期的完成情况总评评出最佳,会有神秘大奖。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-5-16 12:07:53 | 显示全部楼层
本帖最后由 caobynk 于 2016-5-16 13:08 编辑

  1. # 方法1
  2. from functools import reduce
  3. def c(n, k):
  4.     if k==0 or k == n:
  5.         return 1
  6.     else:
  7.         return reduce(lambda x,y: x*y, list(range(k+1, n+1)))/reduce(lambda x,y: x*y, list(range(1, n-k+1)))
  8.    
  9. def numRoad(n):
  10.     result = 0
  11.     for k in range(1, n+1):
  12.         result = result + c(n-1, k-1) * c(n+1, k)
  13.     return result

  14. # 方法2
  15. def numroad(n):
  16.     nnew = [0]
  17.     for k in range(1, n+1):
  18.         nlast = nnew
  19.         nnew[0] = 1
  20.         for i in range(1, k):
  21.             nnew[i] = nnew[i-1] + nlast[i]
  22.         nnew.append(2*nnew[k-1])
  23.     return nnew[-1]

  24. if __name__ == '__main__':
  25.     n = 20
  26.     print('Method1:' + str(n) + '*' + str(n) + '网格路径共有' + str(numRoad(n)) + '条')
  27.     print('Method2:' + str(n) + '*' + str(n) + '网格路径共有' + str(numroad(n)) + '条')


复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-16 12:17:47 | 显示全部楼层
本帖最后由 holdme 于 2016-5-16 17:21 编辑

用组合数学求解很方便:
横竖总共要走40步,其中横20步,竖20步,其实就是C40取20
这样的话,一行就能解决计算部分了
  1. import math
  2. import time
  3. start = time.clock()
  4. print('从20*20的网格的左上角通往右下角有%s条路'%str(int(math.factorial(20)/math.factorial(10)/math.factorial(10))))
  5. print('用时%s秒'%str(time.clock()-start))
复制代码

答案是:
  1. 从20*20的网格的左上角通往右下角有137846528820条路
  2. 用时3.0443930882029235e-05秒
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-16 14:26:48 | 显示全部楼层
本帖最后由 DingRan 于 2016-5-16 18:10 编辑

严重支持

首先,
用排列组合即可解决:
即:20个“向右”和20个“向下”共有几种排法?
C(40,20)=40!/20!/20!=137846528820

但毕竟是一道编程题~先占坑~

填坑~
  1. import time

  2. d = {}#储存单步运算的结果,避免重复计算

  3. #迭代函数
  4. def f(x,y):
  5.     if (x,y) in d:
  6.         return d[(x,y)]
  7.    
  8.     if x==0 and y!=0:
  9.         d[(x,y)] = f(x,y-1)
  10.         return f(x,y-1)

  11.     if x!=0 and y==0:
  12.         d[(x,y)] = f(x-1,y)
  13.         return f(x-1,y)

  14.     if x==0 and y==0:
  15.         d[(x,y)] = 1
  16.         return 1

  17.     if x!=0 and y!=0:
  18.         d[(x,y)] = f(x-1,y)+f(x,y-1)
  19.         return f(x-1,y)+f(x,y-1)

  20. m = 20

  21. a = time.clock()
  22. print('结果:%s' %f(m,m))
  23. b = time.clock()

  24. print('用时:%.3fs'%(b-a))
复制代码

运行结果:
  1. >>>
  2. 结果:137846528820
  3. 用时:0.010s
  4. >>>
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-16 22:04:07 | 显示全部楼层
  1. def fun1(m,n):
  2.     lis3=[1 for x in range(1,n+1)]
  3.     for i in range(m):
  4.         lis4=[]
  5.         for j in range(n):
  6.             lis4.append(sum(lis3[:j+1])+1)
  7.         lis3=lis4[:]
  8.     print('对于%dx%d的网格,这样的路有%d条' %(m,n,lis3.pop()))

  9. fun1(20,20)
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-17 09:17:32 | 显示全部楼层
本帖最后由 bacon6581 于 2016-5-20 10:47 编辑

其实这道题就是排列组合的问题。
20x20的格子,从左上角走至右下角
不管哪种走法,横着要走20格,竖着要走20格。一共要走40格
-------------------------
那么我们就在要走的40格里,排列出横着走20格的所有组合(横的20格确定了,剩下的20格就是竖的)
根据排列组合公式:
1.jpg
计算如下:
1.jpg
---------------------------
补充下:公式写成这样更好理解点
C40取20 * C20取20(在40格里取20格,放横着的;剩下的20格里取20格放竖着的)
因为C20取20等于1
又化简成上图的公式了
---------------------------

可能不好理解,解释下:
1.jpg
横着走用‘-’,竖着走用‘|’
那么上图的六种组合:
--||          -|-|             -||-
|--|          |-|-             ||--

每个图横着走两步,竖着走两步。共走4步
C4取2 = 4!/(2!(4-2)!)=4*3*2/2/2=6

------------------------------------------------
按要求写点代码吧
  1. from time import time

  2. n=int(input('Input a number:'))

  3. start=time()

  4. def jiecheng(m):
  5.     num=1
  6.     while m>1:
  7.         num*=m
  8.         m-=1
  9.     return num

  10. result=jiecheng(n*2)/jiecheng(n)/jiecheng(n)
  11. print('result is :' + str(result))
  12. print("Use time is :" + str(time()-start))
复制代码

结果如图:
1.jpg

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-17 11:34:49 | 显示全部楼层
本帖最后由 小剑剑 于 2016-5-17 11:36 编辑

又是数学题。。
  1. def fun(n=20,m=20):
  2.     accu1=1
  3.     if n>m:
  4.         n,m=m,n
  5.     i=n+m
  6.     count=0
  7.     while count<n:
  8.         accu1*=i
  9.         i-=1
  10.         count+=1
  11.     i=2
  12.     accu2=1
  13.     while i<=n:
  14.         accu2*=i
  15.         i+=1
  16.     return accu1//accu2
复制代码

这个答案就是我们高中时学的C40(下标)20(上标)

补个图

补个图

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-17 12:56:58 | 显示全部楼层
本帖最后由 老忘 于 2016-5-17 18:15 编辑

如果楼主不给个找规律的提示,可能我解不出来这道题,呵呵!说实话,找规律所花的时间比编代码的时间要多得多啊!

在解法中我假定方格的左上角坐标为(0,0),则20个方格,最右下角的坐标为(20,20)

  1. #-*- coding: UTF-8 -*-
  2. int_num=20    #设置网格数为20
  3. dict_result={}    #定义一个空字典,存放坐标点为key及(0,0)点到该坐标的路径数

  4. for x in range(0,int_num+1):    #从(0,0)坐标开始循环处理,计算从(0,0)到(x,y)的路径数
  5.     for y in range(0,int_num+1):
  6.         if x==0 or y==0:    #如果是(0,y)或(x,0)坐标的点,则将(0,0)到该坐标的路径数赋值为1(因为不允许往走),并存入字典
  7.             dict_result[x,y]=1
  8.         else:    #否则,将(0,0)到(x,y)坐标对应的路径数则赋值为(x,y)其相临两个坐标(x或y少1)的路径数之和,并存入字典
  9.             dict_result[x,y]=dict_result[x,y-1]+dict_result[x-1,y]

  10. print(dict_result[int_num,int_num])
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-17 21:12:25 | 显示全部楼层
  1. # encoding = "utf - 8"
  2. __author__ = 'MG'
  3. def TrackSum(n):
  4.     fenZi = 1
  5.     fenMu = 1
  6.     for i in range(n + 1,n + n + 1):
  7.         fenZi *= i
  8.         fenMu *= (i - n)

  9.     return fenZi // fenMu

  10. if __name__ == "__main__":
  11.     print(TrackSum(20))
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-17 21:42:47 | 显示全部楼层
本帖最后由 kmh 于 2016-5-17 22:47 编辑
  1. import math
  2. math.factorial(40)/(math.factorial(20)*math.factorial(20))
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-18 11:32:10 | 显示全部楼层
  1. n = int(input("请输入N×N网格数:"))
  2. a = 1
  3. b = 1

  4. for i in range(2*n,2*n-n,-1):
  5.     a = a * i
  6. for i in range(n,1,-1):
  7.     b = b * i

  8. c = a / b

  9. print("有%s条最短路径" % str(c))
  10.    
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-18 14:03:44 | 显示全部楼层
  1. from time import clock
  2. ts=clock()
  3. a=[[0 for i in range(20)] for i in range(20)]
  4. for i in range(20):
  5.     for j in range(20):
  6.         if i==0:
  7.             a[i][j]=j+2
  8.         else:
  9.             a[i][j]=1
  10.             for m in range(j+1):
  11.                 a[i][j]+=a[i-1][m]
  12. print('从20*20的网格的左上角通往右下角有%d条路' % a[19][19])
  13. print(clock()-ts)
复制代码
  1. 从20*20的网格的左上角通往右下角有137846528820条路
  2. 0.002599226197788156
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-19 09:27:53 | 显示全部楼层
  1. #coding:utf-8
  2. dt = {'00':0}
  3. le = input('输入格数:')
  4. for i in range(1,int(le)+1):
  5.     dt[(0,i)]=1
  6.     dt[(i,0)]=1
  7. for i in range(0,int(le)):
  8.     for j in range(0,int(le)):
  9.         dt[(i+1,j+1)]=dt[(i,j+1)]+dt[(i+1,j)]

  10. print(dt[(int(le),int(le))])
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-20 16:29:52 | 显示全部楼层
  1. def path(row, column):
  2.     lst = [[1 for x in range(column+1)] for x in range(row+1)]
  3.     for r in range(1,row+1):
  4.         for c in range(1,column+1):
  5.             lst[r][c] = lst[r-1][c] + lst[r][c-1]
  6.     return lst.pop().pop()

  7. print(path(20,20))
复制代码

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
冬雪雪冬 + 5 + 5 热爱鱼C^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-5-22 21:19:57 | 显示全部楼层
一开始是想把起点和终点设定为x,y都为20的点,然后每一次横向和纵向移动就分别减1,然后按照这个思路看了一下,发现。。其实路径数就是等于除了起点和终点以外点的个数。。也就是21*21-2。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-2 14:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表