CCNU算法設計作業,僅供參考0.0
自己動手,豐衣足食QAQ更新全看心情
Task-1
1.輸入一個自然數(<90000), 分別用遞歸法和非遞歸法求其二進制表示.
# -*- coding: utf-8 -*- # @Time : 2019/10/10 21:29 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : binary.py # @Software: PyCharm
#recursion
def recursion(n): result = ''
if n == 0: return result else: result = recursion(n//2) return result + str(n%2) num_a = int(input("input a decimal number : ")) if num_a >= 90000: print("error!") else: print(recursion(num_a)) #non-recursion
def non_recursion(n): s = ''
while n > 0: s = str(n%2) + s # 取余后更新 s
n = n//2 # 取整后更新 n
return s num_b = int(input("input another decimal number : ")) if num_b >= 90000: print("error!") else: print(non_recursion(num_b))
運行截圖:
考慮邊界情況
隨機數情況
2. 分別用遞歸法和非遞歸法求Fibonacci數列的前1000位,並比較計算時間的差異.
# -*- coding: utf-8 -*- # @Time : 2019/10/11 0:25 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : Fibonacci.py # @Software: PyCharm
import time #recursion
def fib_recursion(n): if n == 1: return 1
elif n == 2: return 1
else: return fib_recursion(n-1) + fib_recursion(n-2) num_a = int(input("input a number : ")) tic = time.process_time() if num_a==0: print("error!") else: print(fib_recursion(num_a)) toc = time.process_time() print("time : "+ str(1000*(toc-tic))) #non_recursion
def fib_loop(n): a = 0 b = 1 c = 0 for i in range(n): c = a + b a = b b = c return a num_b = int(input("input a number : ")) tic = time.process_time() if num_b==0: print("error!") else: print(fib_loop(num_b)) toc = time.process_time() print("time : " + str(1000 * (toc - tic))) #another method
class Fibonacci(object): ''' 斐波那契數列迭代器 '''
def __init__(self,n): ''' :param n: int 指的是生成數列的個數 ''' self.n = n #保存當前生成的數列的第幾個數據 生成器中性質,記錄位置,下一個位置的數據
self.current = 0 self.a = 0 self.b = 1
def __next__(self): ''' :return:當前使用next()函數調用時,就會獲取下一個數 '''
if self.current<self.n: self.a,self.b = self.b,self.a+self.b self.current +=1
return self.a else: raise StopIteration def __iter__(self): ''' :return: 迭代器的__iter__返回自身即可 '''
return self if __name__ == '__main__': num_c = int(input("input a number : ")) fib = Fibonacci(num_c) for n in fib: print(n)
運行截圖:
當計算第1000個數的時候會報錯,超過最大遞歸深度。但是經過其他隨機測試可得codes並無錯誤,但是該怎么解決還在思考中。嘗試進行第999個數的計算可行,計算時間超長。
利用datatime模塊可以計算並比較遞歸與非遞歸的時間差異。
e.g. input a number:35 //已經時間放大1000倍便於觀察比較。
/*后記*/老師要求只求出第50個斐波那契數即可,其實50層迭代的斐波那契數的計算也需要非常多的時間。以30層斐波那契數的計算時間為5s為基礎。第50個斐波那契數的計算時間是第30個數的計算的1048,576倍。i7-7700HQ大概需要計算145小時。(當然可能是我計算失誤,不是這個時間)
3.用遞歸算法完成如下問題:有52張牌,使它們全部正面朝上,第一輪是從第2張開始,凡是2的倍數位置上的牌翻成正面朝下;第二輪從第3張牌開始,
凡是3的倍數位置上的牌,正面朝上的翻成正面朝下,正面朝下的翻成正面朝上;第三輪從第4張牌開始,凡是4的倍數位置上的牌按上面相同規則翻轉,
以此類推,直到第一張要翻的牌超過52為止。統計最后有幾張牌正面朝上,以及它們的位置號.
# -*- coding: utf-8 -*- # @Time : 2019/10/11 18:42 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : card.py # @Software: PyCharm
#non_recursion
s = [0]*52
print("initial state : ",s,"\n") for i in range(1,52): for j in range(i,52): if((j+1)%(i+1)==0): if(s[j]==0): s[j]=1
else: s[j]=0 print("ending state : ",s,"\n") vec = [x+1 for x in range(52) if s[x]==0] print("index : ",vec,"\n") #recursion
s = [0]*52
print("initial state : ",s,"\n") def turn_card(n): if(n>52): return
else: for j in range(n,52): if ((j + 1) % (n + 1) == 0): if (s[j] == 0): s[j] = 1
else: s[j] = 0 turn_card(n+1) turn_card(1) print("ending state : ", s, "\n") vec = [x+1 for x in range(52) if s[x]==0] print("index : ",vec,"\n")
運行截圖:
4.一個射擊運動員打靶,靶一共有10環,連開6槍打中45環的可能性有多少種? (每一槍最少是0環,最多是10環)
# -*- coding: utf-8 -*- # @Time : 2019/10/12 11:29 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : shooting.py # @Software: PyCharm
times = 0 def shooting(n,sum): global times if n<0: return
elif (45 - sum)>(10*(n)): return
elif (sum == 45) and (n == 0): times += 1
return
for i in range(11): shooting(n - 1,sum + i) shooting(6,0) print('there are %d possibilities'%times)
運行截圖:
5.在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,輸出所有擺法。
# -*- coding: utf-8 -*- # @Time : 2019/10/12 17:00 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : queens.py # @Software: PyCharm def is_rule(queen_tup, new_queen): """ :param queen_tup: 棋子隊列,用於保存已經放置好的棋子,數值代表相應棋子列號 :param new_queen: 被檢測棋子,數值代表列號 :return: True表示符合規則,False表示不符合規則 """ num = len(queen_tup) for index, queen in enumerate(queen_tup): if new_queen == queen: # 判斷列號是否相等 return False if abs(new_queen - queen) == num - index: # 判斷列號之差絕對值是否與行號之差相等 return False return True def arrange_queen(num, queen_tup=list()): """ :param num:棋盤的的行數,當然數值也等於棋盤的列數 :param queen_tup: 設置一個空隊列,用於保存符合規則的棋子的信息 """ for new_queen in range(num): # 遍歷一行棋子的每一列 if is_rule(queen_tup, new_queen): # 判斷是否沖突 if len(queen_tup) == num - 1: # 判斷是否是最后一行 yield [new_queen] # yield關鍵字 else: # 若果不是最后一行,遞歸函數接着放置棋子 for result in arrange_queen(num, queen_tup + [new_queen]): yield [new_queen] + result for i in arrange_queen(8): print(i)
運行截圖(部分):
Task-2
迷宮問題:設有8*8的方格迷宮,入口和出口分別在左上角和右上角,迷宮格子中分別有0和1,1代表不能走,
迷宮走的規則如圖。當迷宮給出后,找到一條從入口到出口的通路。
源代碼:
-*- coding: utf-8 -*- # @Time : 2019/10/19 10:26 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : mzae.py # @Software: PyCharm import numpy as np maze =np.array ([ [0, 0, 0, 0, 0, 0, 1, 0], [1, 0, 1, 1, 1, 1, 1, 0], [0, 1, 0, 0, 1, 0, 0, 1], [0, 0, 1, 1, 0, 1, 0, 1], [0, 1, 0, 0, 0, 1, 1, 0], [0, 1, 1, 1, 1, 1, 0, 1], [0, 0, 1, 1, 1, 0, 1, 1], [1, 1, 0, 0, 1, 0, 0, 0], ]) p = np.array([1, 1, 1, 1, 1, 1, 1, 1]) q = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) a = np.insert(maze, 0, values=p, axis=1) b = np.insert(a, 9,values=p, axis=1) c = np.insert(b, 0, values=q, axis=0) d = np.insert(c, 9, values=q, axis=0) print("初始化迷宮:") print(d)#為解決越界問題 初始化迷宮 dirs = [lambda x, y: (x + 1, y), lambda x, y: (x - 1, y), lambda x, y: (x, y - 1), lambda x, y: (x, y + 1), lambda x, y: (x + 1, y - 1), lambda x, y: (x + 1, y + 1), lambda x, y: (x - 1, y - 1), lambda x, y: (x - 1, y + 1) ] def mpath(x1, y1, x2, y2): stack = [] #建立抽象棧 stack.append((x1, y1)) #加入初始點 d[x1][y1] = -1 #表示已經走過 while len(stack) > 0: curNode = stack[-1] if curNode == (x2, y2): print(stack) return True for dir in dirs: nextNode = dir(curNode[0], curNode[1]) if d[nextNode[0]][nextNode[1]] == 0 : #找到了下一個 stack.append(nextNode) d[nextNode[0]][nextNode[1]] = -1 # 標記為已經走過,防止死循環 break else: #八個方向都沒找到 d[curNode[0]][curNode[1]] = -1 # 死路一條,標記下次不走 stack.pop() #回溯 print("沒有路") return False mpath(1,1,8,8)
運行截圖:
Task-3
1.利用動態規划算法求解編輯距離問題,給定兩個字符串,求由一個轉成另一個所需的最少編輯操作次數。許可的編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符
# -*- coding: utf-8 -*- # @Time : 2019/12/1 17:25 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : Edit_Distance.py # @Software: PyCharm ''' 利用動態規划算法求解編輯距離問題 ''' def minDistance(word1, word2): ''' :param word1: 傳入字符串word1 :param word2: 傳入字符串Word2 :return: 返回距離矩陣元素 ''' m = len(word1) n = len(word2) if m == 0: return n if n == 0: return m dp = [[0] * (n+1) for _ in range(m+1)] #初始化表格[m+1, n+1] # 計算邊界 for i in range(1, m+1): dp[i][0] = i for j in range(1, n+1): dp[0][j] = j for i in range(1, m+1): #計算dp for j in range(1, n+1): if word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = min(dp[i-1][j-1]+1, dp[i][j-1]+1, dp[i-1][j]+1) return dp[m][n] if __name__ == "__main__": dis = minDistance('www.ccnu.edu.cn', 'www.neu.edu.cn') print("The longest Edit Distance is :", dis)
運行截圖
2.用動態規划算法求最長公共子序列問題.
# -*- coding: utf-8 -*- # @Time : 2019/12/1 17:32 # @Author : BaoBao # @Mail : baobaotql@163.com # @File : LCS.py # @Software: PyCharm import numpy as np def Longest_Common_Subsequence(a, b): ''' :param a:字符串a :param b:字符串b :return:length subseq ''' length = 0 subseq = '' cell = np.zeros(shape=(len(a), len(b))) for i in range(len(a)): for j in range(len(b)): if a[i] == b[j]: cell[i][j] = cell[i - 1][j - 1] + 1 if cell[i][j] > length: length = cell[i][j] subseq += a[i] else: cell[i][j] = max(cell[i-1][j], cell[i][j-1]) return length, subseq if __name__ == "__main__": a, b = Longest_Common_Subsequence('www.ccnu.edu.cn', 'www.neu.edu.cn') print('The length of longest common subsequence is:%d\nThe Longest Common Subsequence is:%s' % (a, b))
運行截圖
算法分析在本人github上歡迎交流~~~
對你有幫助就支付寶請我喝可樂叭~~~