算法竞赛入门第七章:回溯与路径寻找
2016-08-29 20:49
330 查看
PrimeRing,Uva524:
基本思路:直接回溯即可。注意一个细节每一个长度为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:首先从左到右确定每一个字符,然后检测以该添加的字符为尾部的后缀是否前一半字串等于后一半字串。这样生成的字典序是严格升序排列的。第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))
UVA140:Bandwidth
给定一个图,对于图中所有点的任何一个排列,定义带宽为:所有点与其图中相邻点在排列中的距离的最大值。求出一个图的最小带宽。
基本思路:直接枚举全排列效率太低,回溯时候可以剪掉一些节点:(1)当某一个节点导致带宽大于最优值时,则不必继续扩展。(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]: for adj in graph[each]: 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 for adj in graph[i]: if not vis[adj]: 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)
天平难题:uva1354
直接暴力枚举,但是枚举的思路是从底层向上开始,每次选择两个节点构造一个新的节点。最后求解宽度则分别算出左边边界和右边边界距离中心的距离,最后相加。这道题讨论了搜索的对象.
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)
Uva 10603:倒水问题。给定三个杯子,容量分别为a,b,c。第三个杯子装满水。没有刻度,要求通过三个杯子之间互相倒水,达到某一个杯子的水量是d。且求出最小的倒水数量。最后,如果不能达到,则求出最接近d的d’。同时求出最小倒水数量。
(1)这道题也是直接利用bfs的思路来进行路径搜索的,但是要求到水量最少,因此我们的就必须要每次拿出倒水量最小的节点来进行扩展,这需要引入优先队列。
(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: vis.add(new[1:]) 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))
Uva1601
这道题有以下几个难点
(1):移动的物体的数量是n,这不是一个固定值,我采取的办法是利用递归来生成所有的状态。而标准答案的算法则是固定n为3,然后将n小于3的状态置位假节点。
(2):通过预处理将所有的空节点生成一个图,这样遍历的时候就不需要遍历5*5*5次了。
(3):需要避开两个物体交换位置的情况以及占用同一位置的情况。
最后一个小技巧,利用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): adj = walk(p,k) if check(adj): nodes_table[p].append(adj) 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: states.add(new) q.append(new+(now +1,)) return for next in adj_table[now[cur][:n]]: 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) adj_table = construct(graph) q = deque() start = tuple([p for p in ans_pos]+[0]) states.add(start[:n]) 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.5 路径寻找问题 例题7-9 UVa1601(1)
- 算法竞赛入门经典:第七章 暴力求解法 7.3分数拆分
- 算法竞赛入门经典:第七章 暴力求解法 7.18倒水问题
- 算法竞赛入门经典:第七章 暴力求解法 7.4双基回文数
- 算法竞赛入门-回溯-7.4.1-八皇后问题
- A*路径寻找算法入门(转)
- 算法竞赛入门第七章(2):枚举排列和子集
- 《AI for Game Developers》第七章 A*路径寻找算法 (二)(skiplow翻译)
- 算法竞赛入门第七章:迭代加深搜索
- 算法竞赛入门指南第七章
- A*路径寻找算法入门
- A*路径寻找算法入门
- 算法竞赛入门第七章(1):暴力枚举
- 算法竞赛入门经典第七章暴力求解法——枚举排列(记录向)
- 算法竞赛入门第七章:习题
- 《AI for Game Developers》第七章 A*路径寻找算法 (三)(skiplow翻译)
- 算法竞赛入门经典:第六章 数据结构基础 6.12迷宫路径
- 算法竞赛入门经典:第七章 暴力求解法 7.10 二进制法
- 《AI for Game Developers》第七章 A*路径寻找算法 (一)(skiplow翻译)
- 算法竞赛入门第七章:竞赛选讲(Uva12325,Uva1603)