|
发表于 2017-2-13 10:09:57
|
显示全部楼层
本帖最后由 jerryxjr1220 于 2017-2-15 13:49 编辑
之前的python小练习正好讲到了“广度优先搜索”,“深度优先搜索”和“A*算法”,这题正好可以利用这3种方法来求解,顺便我们可以比较一下这3种方法之间的效率。
第一种方法:广度优先搜索
思路: 既然是广度优先搜索,当然是按照节点,从上到下依次加入候选列表,然后依次进行判断(顺序是从前到后),看是否符合条件要求(即两两组合能构成素数),如果符合则再加入候选列表,如果不符合就判断下一个。(我其中用了字典的方法帮助加快搜索)
代码:
- import time
- start = time.time()
- primes = [True]*10000
- primes[0], primes[1] = False, False
- for i, prime in enumerate(primes):
- if prime:
- for j in range(i*i,10000,i):
- primes[j] = False
- plist = [k for k, trueprime in enumerate(primes) if trueprime]
- plist.remove(2)
- plist.remove(5)
- def isprime(n):
- global plist,primes
- if n<10000:
- return primes[n]
- else:
- for p in plist:
- if n % p == 0: return False
- if p*p > n: return True
- queue = [[each] for each in plist]
- visited = {}
- while len(queue)>0:
- qu = queue.pop(0)
- for p in plist:
- if p in qu:
- continue
- flag = True
- for q in qu:
- ss = (p,q)
- if ss not in visited:
- if isprime(int(str(p)+str(q))) and isprime(int(str(q)+str(p))):
- visited[ss] = True
- else:
- visited[ss] = False
- flag = False
- break
- else:
- if visited[ss] == False:
- flag = False
- break
- if flag:
- qu.append(p)
- if len(qu) > 4:
- print('Bingo!', qu)
- print(sum(qu))
- print('BFS--Time used: %.3f sec' % (time.time()-start))
- exit()
- queue.append(qu)
复制代码
输出:
Bingo! [5701, 13, 5197, 6733, 8389]
26033
BFS--Time used: 13.709 sec
第二种方法:深度优先搜索
思路:利用回溯法进行搜索判断,递归深度最大5层。深度优先搜索在搜索范围很大,而搜索深度又很浅的情况下,优势非常明显(比如本题)。
代码:
- import time
- start = time.time()
- primes = [True]*10000
- primes[0], primes[1] = False, False
- for i, prime in enumerate(primes):
- if prime:
- for j in range(i*i,10000,i):
- primes[j] = False
- plist = [str(k) for k, trueprime in enumerate(primes) if trueprime]
- plist.remove('2')
- plist.remove('5')
- visited = {}
- def isprime(n):
- global plist,primes
- if n<10000:
- return primes[n]
- else:
- for p in plist:
- p = int(p)
- if n % p == 0: return False
- if p*p > n: return True
- def find(p=0,lst=[]):
- global plist,visited
- if len(lst) > 4:
- print('Bingo!', lst)
- print(sum([int(i) for i in lst]))
- print('DFS--Time used: %.3f sec' % (time.time()-start))
- exit()
- if p >= len(plist): return
- for q in range(p,len(plist)):
- a = plist[q]
- if len(lst) == 0:
- lst.append(a)
- find(p+1,lst)
- lst.pop()
- else:
- flag = True
- for b in lst:
- ss = (a,b)
- if ss not in visited:
- if isprime(int(a+b)) and isprime(int(b+a)):
- visited[ss] = True
- else:
- visited[ss] = False
- flag = False
- break
- else:
- if visited[ss] == False:
- flag = False
- break
- if flag:
- lst.append(a)
- find(p+1,lst)
- lst.pop()
- find()
复制代码
输出:
Bingo! ['13', '5197', '5701', '6733', '8389']
26033
DFS--Time used: 4.441 sec
第三种方法:A*算法:
思路:A*算法是综合了广度优先搜索和深度优先搜索的算法,代码结构几乎和广度优先搜索一致,但是搜索顺序却是从后往前(由于满足条件新加入的候选组合也是加入在列表的末尾),所以实际搜索顺序又是按照了深度优先搜索的方法,如果一条子路径一直能满足条件,则优先搜索新加入的子路径,直到新的子路径不满足要求,再切换到下一个候选组合。所以这个方法在搜索宽度很大而搜索深度又比较浅的情况下(比如本题),比起广度优先算法要快很多。
- import time
- start = time.time()
- primes = [True]*10000
- primes[0], primes[1] = False, False
- for i, prime in enumerate(primes):
- if prime:
- for j in range(i*i,10000,i):
- primes[j] = False
- plist = [k for k, trueprime in enumerate(primes) if trueprime]
- plist.remove(2)
- plist.remove(5)
- def isprime(n):
- global plist,primes
- if n<10000:
- return primes[n]
- else:
- for p in plist:
- if n % p == 0: return False
- if p*p > n: return True
- queue = [[each] for each in plist]
- visited = {}
- while len(queue)>0:
- qu = queue.pop()
- for p in plist:
- if p in qu:
- continue
- flag = True
- for q in qu:
- ss = (p,q)
- if ss not in visited:
- if isprime(int(str(p)+str(q))) and isprime(int(str(q)+str(p))):
- visited[ss] = True
- else:
- visited[ss] = False
- flag = False
- break
- else:
- if visited[ss] == False:
- flag = False
- break
- if flag:
- qu.append(p)
- if len(qu) > 4:
- print('Bingo!', qu)
- print(sum(qu))
- print('A*--Time used: %.3f sec' % (time.time()-start))
- exit()
- queue.append(qu)
复制代码
输出:
Bingo! [8389, 13, 5197, 5701, 6733]
26033
A*--Time used: 5.218 sec
结论:
当搜索宽度较大,搜索深度又很浅的情况下(比如本题),效率从高到低依次为:深度优先搜索>A*算法>广度优先搜索。
同理,可以推断,当搜索宽度很小,搜索深度又很深的情况下,效率从高到低依次为:广度优先搜索>A*算法>深度优先搜索。
而当搜索宽度和深度都差不多或者不确定的情况下,A*算法则有比较明显的优势(效率几乎接近最优算法,而且程序代码比较容易写,不用考虑递归(对于新手比较容易掌握))。 |
评分
-
查看全部评分
|