E:/GitHub/suanfaquti/Q31计算最短路径1.py
'''
问题描述
一个边长n的正方形划分成n*n个边长1的小正方形,所有的边和点构成一张图,
求从左上到与右下再返回左上的所有最短路径中没有经过重复线段的路径数。
例如n=2时一共有10种往返路径。求n=6时,共有多少种最短路径?
分析
本题可转化成从左上同时找两条路径到右下,要求路径最短且无重复。
显然每次只能往右或者下走。对每一个点(x,y)维护一个二维数组(a,b),
a表示两条路径走到(x,y)才重复的路径数,b表示走到(x,y)都不重复的路径数,
显然(7,7)的b就是答案。由于(x,y)的上一点是(x-1,y)或者(x,y-1),
那么(x,y)的a就等于(x-1,y)的b和(x,y-1)的b的和;
而(x,y)的b就是(x,y)的所有路径数减去所有重复路径数,
所有路径数是comb(x+y,x)的平方,所有重复路径数就是[1-x][1-y]的所有点的
走到该点才重复的路径数 乘以 该点到终点的所有路径数的平方,
即代码里的 comb(x-i+y-j,y-j)**2*res[i][j][0]
'''
from scipy.special import comb, perm
n=7
res=[[[0,0] for i in range(n+1)] for j in range(n+1)]
for x in range(1,n+1):
for y in range(1,n+1):
if x>y:
res[x][y]=res[y][x]
continue
res[x][y][0]=res[x-1][y][1]+res[x][y-1][1]
b=comb(x-1+y-1,x-1)**2
for i in range(1,x+1):
for j in range(1,y+1):
b-=comb(x-i+y-j,y-j)**2*res[i][j][0]
res[x][y][1]=b
for i in range(n+1):
print(res[i]) #100360
'''
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[[0, 0], [0, 1.0], [1.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]
[[0, 0], [1.0, 0.0], [0.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [4.0, 10.0], [12.0, 20.0], [22.0, 32.0], [34.0, 46.0], [48.0, 62.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [12.0, 20.0], [40.0, 80.0], [112.0, 204.0], [250.0, 418.0], [480.0, 752.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [22.0, 32.0], [112.0, 204.0], [408.0, 786.0], [1204.0, 2244.0], [2996.0, 5312.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [34.0, 46.0], [250.0, 418.0], [1204.0, 2244.0], [4488.0, 8592.0], [13904.0, 26200.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [48.0, 62.0], [480.0, 752.0], [2996.0, 5312.0], [13904.0, 26200.0], [52400.0, 100360.0]]
'''
'''
问题描述
一个边长n的正方形划分成n*n个边长1的小正方形,所有的边和点构成一张图,
求从左上到与右下再返回左上的所有最短路径中没有经过重复线段的路径数。
例如n=2时一共有10种往返路径。求n=6时,共有多少种最短路径?
分析
本题可转化成从左上同时找两条路径到右下,要求路径最短且无重复。
显然每次只能往右或者下走。对每一个点(x,y)维护一个二维数组(a,b),
a表示两条路径走到(x,y)才重复的路径数,b表示走到(x,y)都不重复的路径数,
显然(7,7)的b就是答案。由于(x,y)的上一点是(x-1,y)或者(x,y-1),
那么(x,y)的a就等于(x-1,y)的b和(x,y-1)的b的和;
而(x,y)的b就是(x,y)的所有路径数减去所有重复路径数,
所有路径数是comb(x+y,x)的平方,所有重复路径数就是[1-x][1-y]的所有点的
走到该点才重复的路径数 乘以 该点到终点的所有路径数的平方,
即代码里的 comb(x-i+y-j,y-j)**2*res[i][j][0]
'''
from scipy.special import comb, perm
n=7
res=[[[0,0] for i in range(n+1)] for j in range(n+1)]
for x in range(1,n+1):
for y in range(1,n+1):
if x>y:
res[x][y]=res[y][x]
continue
res[x][y][0]=res[x-1][y][1]+res[x][y-1][1]
b=comb(x-1+y-1,x-1)**2
for i in range(1,x+1):
for j in range(1,y+1):
b-=comb(x-i+y-j,y-j)**2*res[i][j][0]
res[x][y][1]=b
for i in range(n+1):
print(res[i]) #100360
'''
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[[0, 0], [0, 1.0], [1.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]
[[0, 0], [1.0, 0.0], [0.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0], [2.0, 2.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [4.0, 10.0], [12.0, 20.0], [22.0, 32.0], [34.0, 46.0], [48.0, 62.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [12.0, 20.0], [40.0, 80.0], [112.0, 204.0], [250.0, 418.0], [480.0, 752.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [22.0, 32.0], [112.0, 204.0], [408.0, 786.0], [1204.0, 2244.0], [2996.0, 5312.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [34.0, 46.0], [250.0, 418.0], [1204.0, 2244.0], [4488.0, 8592.0], [13904.0, 26200.0]]
[[0, 0], [0.0, 0.0], [2.0, 2.0], [48.0, 62.0], [480.0, 752.0], [2996.0, 5312.0], [13904.0, 26200.0], [52400.0, 100360.0]]
'''