算法竞赛入门第七章：回溯与路径寻找

基本思路：直接回溯即可。注意一个细节每一个长度为n的环对应n种排列,因此输出要求固定第一个值为1。

Primes = set([2, 3, 5, 7,  11, 13, 17, 19, 23, 29, 31])

def is_prime(x): return x in Primes
vis = [0] * (16 + 2)
C = [0] * (16 + 2)

def prime_ringe(cur, n):
if cur == n:
if is_prime(C[0] + C[n - 1]):
print(C[0:n])
return
for i in range(2, n + 1):
if not vis[i] and (cur == 0 or is_prime(i + C[cur - 1])):
C[cur], vis[i] = i, 1
prime_ringe(cur + 1, n)
vis[i] = 0

def process():
while 1:
n = input()
if n == 0:
break
C[0] = 1
prime_ringe(1, int(n))

Krpton Factor Uva129:$Uva 129:$首先从左到右确定每一个字符,然后检测以该添加的字符为尾部的后缀是否前一半字串等于后一半字串。这样生成的字典序是严格升序排列的。第k小的字典序就可以确定。

Primes = set([2, 3, 5, 7,  11, 13, 17, 19, 23, 29, 31])

def is_prime(x): return x in Primes
vis = [0] * (16 + 2)
C = [0] * (16 + 2)

def prime_ringe(cur, n):
if cur == n:
if is_prime(C[0] + C[n - 1]):
print(C[0:n])
return
for i in range(2, n + 1):
if not vis[i] and (cur == 0 or is_prime(i + C[cur - 1])):
C[cur], vis[i] = i, 1
prime_ringe(cur + 1, n)
vis[i] = 0

def process():
while 1:
n = input()
if n == 0:
break
C[0] = 1
prime_ringe(1, int(n))

基本思路:直接枚举全排列效率太低,回溯时候可以剪掉一些节点：(1)$(1)$当某一个节点导致带宽大于最优值时,则不必继续扩展。(2)$(2)$当某一个节点有m个节点不确定时,那么最理想的情况带宽是m，若m大于最优带宽,也可用剪掉。

min_bandwidth = 100
n = 9
C = [0] * (n)
D = [0] * (n)
vis = [0] * (n + 1)
fina_ans = None

def find_max(graph):
max_d = 0
for each in C[1:n]:
max_d = max(max_d, abs(D[each] - D[adj]))
return max_d

def Bandwith(graph, cur):
global n, min_bandwidth, fina_ans
if cur == n:
p = find_max(graph)
if min_bandwidth > p:
min_bandwidth = p
fina_ans = C[1:]
return
for i in graph:
ok = True
if not vis[i]:
D[i] = cur
cnt = 0
cnt += 1
if cnt >= min_bandwidth:
ok = False
continue
if abs(D[adj] - D[i]) > min_bandwidth:
ok = False

if ok:
vis[i] = 1
C[cur] = i
Bandwith(graph, cur + 1)
vis[i] = 0
graph = {1: [2, 7, 6], 2: [1, 3, 7], 3: [2, 4], 4: [3, 5, 7],
5: [4, 8], 6: [1, 7, 8], 7: [2, 4, 6], 8: [5, 6]}
Bandwith(graph, 1)
print(fina_ans, min_bandwidth)


直接暴力枚举,但是枚举的思路是从底层向上开始,每次选择两个节点构造一个新的节点。最后求解宽度则分别算出左边边界和右边边界距离中心的距离,最后相加。这道题讨论了搜索的对象.

def weight(node):
if type(node)==int:return node
return node[0]
def width(t):
def find_bound(t,mark):
bound = 0
while type(t)!=int:
c = weight(t[1])+weight(t[2])
bound+=weight(t[mark])/c
t = t[mark]
return bound
b1,b2 = find_bound(t,1),find_bound(t,2)
return b2+b1
def enumerate_tree(vertexs,r):
left,right = 0,0
min_w = r*2
def do(vertexs):
nonlocal min_w
if len(vertexs)==1:
w = width(vertexs[0])
if w <= r:min_w = min(w,min_w)
return
temp = vertexs[::]
for node1 in vertexs:
for node2 in vertexs:
if node1!=node2:
temp.remove(node1);temp.remove(node2)
temp.append((weight(node1)+weight(node2),node1,node2))
do(temp)
temp.append(node1);temp.append(node2)
temp.remove((weight(node1)+weight(node2),node1,node2))
do(vertexs)
print(min_w)
enumerate_tree([1,1,2],3)

(2)$(2)$其次存储状态判重的时候只需要存储三杯水的状态,至于到水量不能作为状态变量。

def solve(a,b,c,d):
cap = [0,a,b,c]
min_state = (0,0,0,c)
start = (0,0,0,c)
vis = set((0,0,c))
water_state = PriorityQueue()
water_state.put(start)
while not water_state.empty():
now = water_state.get()
if d in now[1:]:print(now);return(now[0],d)
if abs(d-min_state[3])>abs(d-now[3]):min_state=now
for i in range(1,4):
for j in range(1,4):
if i!=j:
if now[i]==0 or now[j]==cap[j]:continue
amount = min(now[i],cap[j]-now[j])
new = list(now)
new[0]+=amount;new[i]-=amount;new[j]+=amount
new = tuple(new)
if new[1:] not in vis:
water_state.put(new)
possible_d = min_state[1]
for x in min_state[1:]:
possible_d = min(possible_d,x,key = lambda y:abs(y-d))
return (min_state[0],possible_d)
print(solve(1,12,15,7))

这道题有以下几个难点

最后一个小技巧,利用ord(word)-‘a’自动给物体排好序。

def solve(graph,w,h,n):
direction = {0:(0,0),1:(1,0),2:(0,1),3:(-1,0),4:(0,-1)}
def construct(graph):
nodes_table = {}
for i in range(w):
for j in range(h):
p = (i,j)
nodes_table[p] = []
if graph[i][j]=='#':continue
for k in range(5):
return nodes_table
def walk(p,i):
x,y = p
return (x+direction[i][0],y+direction[i][1])
def create_nodes(q,now,new,cur):
if cur==n:
new=tuple(new)
if check_notswap(now,new) and new not in states:
q.append(new+(now[n]+1,))
return
new.append(next)
create_nodes(q,now,new,cur+1)
new.pop()
def check(next):
x,y = next
if x<w and x>0 and y<h and y>0 and graph[x][y]!='#':return True
return False
def check_notswap(now,new):
for i in range(n):
for j in range(i+1,n):
if new[i]==new[j] or (now[i],now[j])==(new[j],new[i]):return False
return True
def satisfy(now):
for i in range(n):
if now[i]!=capital_pos[i]:return False
return True
def search_capital(ans_pos,capital_pos,graph):
for i in range(w):
for j in range(h):
if str.islower(graph[i][j]):ans_pos[ord(graph[i][j])-ord('a')] = (i,j)
elif str.isupper(graph[i][j]):capital_pos[ord(graph[i][j])-ord('A')] = (i,j)
states = set()
ans_pos,capital_pos = [0]*n,[0]*n
search_capital(ans_pos,capital_pos,graph)
q = deque()
start = tuple([p for p in ans_pos]+[0])
q.append(start)
while len(q):
now = q.popleft()
if satisfy(now):return now
create_nodes(q,now,[],0)
def process():
line = input().split(' ')
h,w,n = [int(x) for x in line]
graph = []
for i in range(w):
line = input()
graph.append(line)
print(solve(graph,w,h,n))
process()

• 本文已收录于以下专栏：

算法竞赛入门经典(第二版)-刘汝佳-第七章 暴力求解法 例题（7/15）

• thudaliangrx
• 2016年03月16日 13:17
• 1611

算法竞赛入门经典(第二版)-刘汝佳-第七章 暴力求解法 习题（2/18）

• thudaliangrx
• 2016年03月16日 13:23
• 1643

算法竞赛入门经典（第2版）2.5注解与习题

p34 编程记录
• qq_37589650
• 2017年04月18日 19:55
• 161

【算法竞赛入门经典】【第三章】课后习题（第一部分）

《算法竞赛入门经典》【第三章】课后习题详解（第一部分） 包含 习题3-1 分数统计（stat） 习题 3-2 单词的长度（word） 习题3-3 乘积末三位 （product）...
• luomingjun12315
• 2015年04月09日 22:45
• 1165

算法竞赛入门经典(第2版)习题2-4详解

#include #define MAXN 100 double a[MAXN]={0};int main() { int n,m,count=0; while(1) { ...
• big_DreamerLzq
• 2016年06月22日 10:17
• 1081

（回溯法） 数据结构_回溯法求解迷宫路径

• h302849781
• 2014年04月16日 23:14
• 1008

算法竞赛第七章

• m0_37253730
• 2017年03月30日 09:44
• 85

《算法竞赛入门经典》第七章7.1，7.2，7.3（总结）

7.1 一般如果让你求a,b满足h（a,b）=k，k为一个固定的函数，可以通过枚举a,然后用k反向求b，来减少一层循环，两个以上情况同理。 1.技巧总结如果求abcdefgh判断他们是否互补相等，...
• JACK_JYH
• 2017年02月05日 00:07
• 232

刘汝佳《算法竞赛入门经典（第二版）》习题（二）

• qq_37653144
• 2017年04月22日 22:16
• 2309

算法竞赛入门经典 习题 2-10 排列（permutation）

• oceaniwater
• 2014年11月02日 14:43
• 2537

举报原因： 您举报文章：算法竞赛入门第七章：回溯与路径寻找 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)