Algorithm n*n网格上所有可能的移动
所以,我必须计算网格左上角和左下角之间所有可能的路径。我的问题来自这样一个事实:每一个广场都必须参观一次。不少于或多于 现在我只是用递归强制它。7x7网格需要约30秒,但8x8需要+24小时(没有让它完成)。我试图通过检查新的递归方法调用是否能够连接到终点来解决这个问题,方法是跟踪边并查看它是否与自身或终点线相交。我还尝试从最后插入的方块“填充”网格。这两种方法都有效,但它们甚至比暴力强迫更慢Algorithm n*n网格上所有可能的移动,algorithm,path-finding,Algorithm,Path Finding,所以,我必须计算网格左上角和左下角之间所有可能的路径。我的问题来自这样一个事实:每一个广场都必须参观一次。不少于或多于 现在我只是用递归强制它。7x7网格需要约30秒,但8x8需要+24小时(没有让它完成)。我试图通过检查新的递归方法调用是否能够连接到终点来解决这个问题,方法是跟踪边并查看它是否与自身或终点线相交。我还尝试从最后插入的方块“填充”网格。这两种方法都有效,但它们甚至比暴力强迫更慢 我想自己发现这一点,但如果能得到一些帮助,我将不胜感激。我很高兴10x10网格可以解决。我是在接近这个
我想自己发现这一点,但如果能得到一些帮助,我将不胜感激。我很高兴10x10网格可以解决。我是在接近这个正确的方向(递归并在执行新的递归方法调用之前检查这个递归分支是否能够达到目标),还是应该使用动态编程或其他方法来接近它?我怀疑是否存在一个封闭形式的公式。不过,动态规划将起作用。高层次的想法是一排一排地工作,记住什么与什么相联系。在一次5x5的旅行中
v>>>v
v^v<<
v^>>v
v^v<<
>^>>.,
标记为-
的顶点不在外部连接。标记为0
的顶点连接到起始正方形。标记为1
的顶点是路径的两端
与行关联的边表示一个分区,分区由行内部的边连接,每个间隔看起来像一个
|___| |___ ___| ___
| | | |
如果非空且仅|
则为。给定一个接口(状态)和一行(字母),我们可以计算组合的接口(如果有效)应该是什么
我的时间很短,你也不需要所有的细节,所以让我把实现这一点的Python 3代码转储掉
#!/usr/bin/env python3
import collections
import itertools
if False:
def all_pairings(m, i):
assert isinstance(m, int)
assert m >= 0
assert isinstance(i, int)
assert i >= 0
if m == 0:
yield ()
else:
for k in range(m):
for p in all_pairings(k, i + 1):
for q in all_pairings(m - 1 - k, i + 1 + k):
yield (i,) + p + (i,) + q
def all_states(n):
assert isinstance(n, int)
assert n >= 0
for m in range(1, (n + 1) // 2 + 1):
for indexes in itertools.combinations(range(n), m * 2 - 1):
state = [None] * n
for k in range(m):
for p in all_pairings(k, 0):
for q in all_pairings(m - 1 - k, k + 1):
for v, i in zip(indexes, p + (k,) + q):
state[v] = i
yield tuple(state)
def connections_from_state(state):
return tuple(v for v, i in enumerate(state) if i is not None)
def all_partitions(n):
assert isinstance(n, int)
assert n >= 0
boundaries = [0, n]
for k in range(n):
for c in itertools.combinations(range(1, n), k):
boundaries[1:-1] = c
yield tuple(boundaries)
def all_letters(n):
assert isinstance(n, int)
assert n >= 0
for partition in all_partitions(n):
factors = []
for i in range(len(partition) - 1):
v = partition[i]
w = partition[i + 1] - 1
factor = [((v, False), (w, True))]
if v != w:
factor.append(((v, False), (w, False)))
factor.append(((v, True), (w, False)))
factor.append(((v, True), (w, True)))
factors.append(factor)
yield from itertools.product(*factors)
def inner_connections_from_letter(letter):
return tuple(x for ends in letter for x, outer_x in ends if not outer_x)
def outer_connections_from_letter(letter):
return tuple(x for ends in letter for x, outer_x in ends if outer_x)
def union_find(n):
return list(range(n))
def find(parent, v):
while parent[v] != v:
parent[v] = parent[parent[v]]
v = parent[v]
return v
def union(parent, v, w):
if v == w:
return True
v = find(parent, v)
w = find(parent, w)
if v < w:
parent[w] = v
return True
elif v == w:
return False
else:
parent[v] = w
return True
def transition(state, letter):
assert connections_from_state(state) == inner_connections_from_letter(letter)
n = len(state)
parent = union_find(n)
other_end = {}
for v, i in enumerate(state):
if i is not None and not union(parent, v, other_end.setdefault(i, v)):
return None
for (v, outer_v), (w, outer_w) in letter:
if not union(parent, v, w):
return None
next_state = [None] * n
label = {}
for v in outer_connections_from_letter(letter):
w = find(parent, v)
if w not in label:
label[w] = len(label)
next_state[v] = label[w]
return tuple(next_state)
def count_paths(n):
counts = collections.Counter({(0,) + (None,) * (n - 1): 1})
letters_from_inner_connections = collections.defaultdict(list)
for letter in all_letters(n):
letters_from_inner_connections[inner_connections_from_letter(letter)].append(letter)
for j in range(n):
next_counts = collections.Counter()
for state, count in counts.items():
for letter in letters_from_inner_connections[connections_from_state(state)]:
next_state = transition(state, letter)
if next_state is not None:
next_counts[next_state] += count
counts = next_counts
return counts[(None,) * (n - 1) + (0,)]
def slow_count_paths_rec(n, i, j, visited):
if len(visited) == n ** 2 and i == n - 1 and j == n - 1:
return 1
elif i < 0 or n <= i or j < 0 or n <= j or (i, j) in visited:
return 0
else:
visited.add((i, j))
total = 0
total += slow_count_paths_rec(n, i - 1, j, visited)
total += slow_count_paths_rec(n, i, j - 1, visited)
total += slow_count_paths_rec(n, i, j + 1, visited)
total += slow_count_paths_rec(n, i + 1, j, visited)
visited.remove((i, j))
return total
def slow_count_paths(n):
return slow_count_paths_rec(n, 0, 0, {(n - 1, n - 1)})
print(slow_count_paths(5))
print(count_paths(5))
#/usr/bin/env蟒蛇3
导入集合
进口itertools
如果为假:
定义所有_对(m,i):
断言isinstance(m,int)
断言m>=0
断言isinstance(i,int)
断言i>=0
如果m==0:
产量()
其他:
对于范围内的k(m):
对于所有_对中的p(k,i+1):
对于所有_对中的q(m-1-k,i+1+k):
产量(i,)+p+(i,)+q
def所有_状态(n):
断言isinstance(n,int)
断言n>=0
对于范围(1,(n+1)//2+1)内的m:
对于itertools.组合中的索引(范围(n),m*2-1):
状态=[None]*n
对于范围内的k(m):
对于所有_对中的p(k,0):
对于所有_对中的q(m-1-k,k+1):
对于v,zip中的i(索引,p+(k,)+q):
状态[v]=i
产量元组(状态)
def连接来自_状态(状态):
返回元组(v代表v,i在枚举(状态)中,如果i不是None)
定义所有分区(n):
断言isinstance(n,int)
断言n>=0
边界=[0,n]
对于范围(n)内的k:
对于itertools.组合中的c(范围(1,n),k):
边界[1:-1]=c
产量元组(边界)
定义所有字母(n):
断言isinstance(n,int)
断言n>=0
对于所有_分区中的分区(n):
因子=[]
对于范围内的i(len(分区)-1):
v=分区[i]
w=分区[i+1]-1
因子=[((v,假),(w,真))]
如果v!=w:
附加因子(((v,False),(w,False)))
附加因子(((v,True),(w,False)))
附加因子(((v,True),(w,True)))
因子。追加(因子)
itertools.产品的产量(*因子)
def内部连接来自字母(字母):
返回元组(x表示x的字母结尾,如果不是外部,则外部x表示结尾)
def外部连接来自字母(字母):
返回元组(x表示x的字母结尾,如果是外部的,则是外部的)
def联合查找(n):
返回列表(范围(n))
def查找(父级,v):
当父母[v]!=五:
父[v]=父[v]]
v=父项[v]
返回v
def接头(主、v、w):
如果v==w:
返回真值
v=查找(父项,v)
w=查找(父项,w)
如果v 如果i<0或n,您可以将您的算法添加到问题中吗
|___| |___ ___| ___
| | | |
#!/usr/bin/env python3
import collections
import itertools
if False:
def all_pairings(m, i):
assert isinstance(m, int)
assert m >= 0
assert isinstance(i, int)
assert i >= 0
if m == 0:
yield ()
else:
for k in range(m):
for p in all_pairings(k, i + 1):
for q in all_pairings(m - 1 - k, i + 1 + k):
yield (i,) + p + (i,) + q
def all_states(n):
assert isinstance(n, int)
assert n >= 0
for m in range(1, (n + 1) // 2 + 1):
for indexes in itertools.combinations(range(n), m * 2 - 1):
state = [None] * n
for k in range(m):
for p in all_pairings(k, 0):
for q in all_pairings(m - 1 - k, k + 1):
for v, i in zip(indexes, p + (k,) + q):
state[v] = i
yield tuple(state)
def connections_from_state(state):
return tuple(v for v, i in enumerate(state) if i is not None)
def all_partitions(n):
assert isinstance(n, int)
assert n >= 0
boundaries = [0, n]
for k in range(n):
for c in itertools.combinations(range(1, n), k):
boundaries[1:-1] = c
yield tuple(boundaries)
def all_letters(n):
assert isinstance(n, int)
assert n >= 0
for partition in all_partitions(n):
factors = []
for i in range(len(partition) - 1):
v = partition[i]
w = partition[i + 1] - 1
factor = [((v, False), (w, True))]
if v != w:
factor.append(((v, False), (w, False)))
factor.append(((v, True), (w, False)))
factor.append(((v, True), (w, True)))
factors.append(factor)
yield from itertools.product(*factors)
def inner_connections_from_letter(letter):
return tuple(x for ends in letter for x, outer_x in ends if not outer_x)
def outer_connections_from_letter(letter):
return tuple(x for ends in letter for x, outer_x in ends if outer_x)
def union_find(n):
return list(range(n))
def find(parent, v):
while parent[v] != v:
parent[v] = parent[parent[v]]
v = parent[v]
return v
def union(parent, v, w):
if v == w:
return True
v = find(parent, v)
w = find(parent, w)
if v < w:
parent[w] = v
return True
elif v == w:
return False
else:
parent[v] = w
return True
def transition(state, letter):
assert connections_from_state(state) == inner_connections_from_letter(letter)
n = len(state)
parent = union_find(n)
other_end = {}
for v, i in enumerate(state):
if i is not None and not union(parent, v, other_end.setdefault(i, v)):
return None
for (v, outer_v), (w, outer_w) in letter:
if not union(parent, v, w):
return None
next_state = [None] * n
label = {}
for v in outer_connections_from_letter(letter):
w = find(parent, v)
if w not in label:
label[w] = len(label)
next_state[v] = label[w]
return tuple(next_state)
def count_paths(n):
counts = collections.Counter({(0,) + (None,) * (n - 1): 1})
letters_from_inner_connections = collections.defaultdict(list)
for letter in all_letters(n):
letters_from_inner_connections[inner_connections_from_letter(letter)].append(letter)
for j in range(n):
next_counts = collections.Counter()
for state, count in counts.items():
for letter in letters_from_inner_connections[connections_from_state(state)]:
next_state = transition(state, letter)
if next_state is not None:
next_counts[next_state] += count
counts = next_counts
return counts[(None,) * (n - 1) + (0,)]
def slow_count_paths_rec(n, i, j, visited):
if len(visited) == n ** 2 and i == n - 1 and j == n - 1:
return 1
elif i < 0 or n <= i or j < 0 or n <= j or (i, j) in visited:
return 0
else:
visited.add((i, j))
total = 0
total += slow_count_paths_rec(n, i - 1, j, visited)
total += slow_count_paths_rec(n, i, j - 1, visited)
total += slow_count_paths_rec(n, i, j + 1, visited)
total += slow_count_paths_rec(n, i + 1, j, visited)
visited.remove((i, j))
return total
def slow_count_paths(n):
return slow_count_paths_rec(n, 0, 0, {(n - 1, n - 1)})
print(slow_count_paths(5))
print(count_paths(5))