Ⅰ c璇璦鎶10鍏冪‖甯佹崲鎴愪簲瑙掍竴瑙掍竴鍏冪殑鍙堝氬皯縐嶆崲鍙
涓浜哄緩璁錛氫粠澶у埌灝忛愭ョ粏鍒嗭紝棣栧厛鎬誨拰10鍏冿紝鍙鍒嗘垚10涓涓鍏冿紝浠庝腑鎷垮嚭涓涓涓鍏冨垎鎴愪袱涓浜旇掞紝鐒跺悗浠庝袱涓浜旇掍腑鎷垮嚭涓涓浜旇掑垎鎴愪簲涓涓瑙掞紝浠ユょ被鎺ㄩ愭ョ粏鍒嗭紱
鍏抽敭鐨勫氨鏄1鍏=2*浜旇掞紱浜旇=5*涓瑙掞紝姣忎笅鍒嗕竴嬈″氨璁╂柟娉曞姞1鈥︹
void main()
{
int a=10,b=0,c=0,way=1;
for(a=10;a>=0;a--)
{
for(b=2*(10-a);b>=0;b--)
{
c+=5;
way++;
}
}
printf("%d\n",way);
}
動態規劃演算法中是將復雜問題遞歸分解為子問題,通過解決這些子問題來解決復雜問題。與遞歸演算法相比,動態編程減少了堆棧的使用,避免了重復的計算,效率得到顯著提升。
先來看一個簡單的例子,斐波那契數列.
斐波那契數列的定義如下。
斐波那契數列可以很容易地用遞歸演算法實現:
上述代碼,隨著n的增加,計算量呈指數級增長,演算法的時間復雜度是 。
採用動態規劃演算法,通過自下而上的計算數列的值,可以使演算法復雜度減小到 ,代碼如下。
下面我們再看一個復雜一些的例子。
這是小學奧數常見的硬幣問題: 已知有1分,2分,5分三種硬幣數量不限,用這些硬幣湊成為n分錢,那麼一共有多少種組合方法。
我們將硬幣的種類用列表 coins 定義;
將問題定義為一個二維數組 dp,dp[amt][j] 是使用 coins 中前 j+1 種硬幣( coins[0:j+1] )湊成總價amt的組合數。
例如: coins = [1,2,5]
dp[5][1] 就是使用前兩種硬幣 [1,2] 湊成總和為5的組合數。
對於所有的 dp[0][j] 來說,湊成總價為0的情況只有一種,就是所有的硬幣數量都為0。所以對於在有效范圍內任意的j,都有 dp[0][j] 為1。
對於 dp[amt][j] 的計算,也就是使用 coins[0:j+1] 硬幣總價amt的組合數,包含兩種情況計算:
1.當使用第j個硬幣時,有 dp[amt-coins[j]][j] 種情況,即amt減去第j個硬幣幣值,使用前j+1種硬幣的組合數;
2.當不使用第j個硬幣時,有 dp[amt][j-1] 種情況,即使用前j種硬幣湊成amt的組合數;
所以: dp[amt][j] = dp[amt - coins[j]][j]+dp[amt][j-1]
我們最終得到的結果是:dp[amount][-1]
上述分析省略了一些邊界情況。
有了上述的分析,代碼實現就比較簡單了。
動態規劃演算法代碼簡潔,執行效率高。但是與遞歸演算法相比,需要仔細考慮如何分解問題,動態規劃代碼與遞歸調用相比,較難理解。
我把遞歸演算法實現的代碼也附在下面。有興趣的朋友可以比較一下兩種演算法的時間復雜度有多大差別。
上述代碼在Python 3.7運行通過。
Ⅲ python n個硬幣中找一個假幣,且已知假幣較輕,怎麼用遞歸和非遞歸兩種方法求
思路:假設有數組arr,裡面的int值代表銀幣重量,下標代表第幾個銀幣。
循環(非遞歸):把數組第一個值賦值給變數tmp,從第二個變數循環到最後一個,比較循環里的變數和tmp值,如果不等,就返回小數下標。
遞歸:用二分思想,銀幣分2堆(不能均分時把中間那個留出來),取重量小的那堆繼續二分。最後只剩下一個時就是所求
下面這種寫法是返回下標的。也可以把硬幣假設成一種數據類型,然後返回那個類型
#!/usr/bin/python
#-*-coding:utf-8-*-
#返回最小值下標
defgetMin(arr1):
iflen(arr1)==0:return-1
tmp=arr1[0]
index=0
forcurinarr1:
iftmp!=cur:
return0iftmp<curelseindex
index+=1
return-1
real_index=0
#返回最小值下標遞歸
defgetMinRecursion(arr1):
globalreal_index
n=len(arr1)
ifn==0:return-1
ifn==1:returnreal_index
ifn==2:returnreal_indexifarr1[0]<arr1[1]elsereal_index+1
sum1=sum(arr1[0:int(n/3)])
sum2=sum(arr1[int(n/3):int(n/3)*2])
ifsum1==sum2:
real_index+=int(n/3)*2
returngetMinRecursion(arr1[int(n/3)*2:n+1])
ifsum1<sum2:
returngetMinRecursion(arr1[0:int(n/3)])
else:
real_index+=int(n/3)
returngetMinRecursion(arr1[int(n/3):int(n/3)*2])
arr=[1,1,1,1,1,1,0,1,1]
print("%d"%getMin(arr))
print("%d"%getMinRecursion(arr))
Ⅳ c璇璦緙栫▼鐢ㄤ竴鍏冧簲瑙掍漢姘戝竵鍏戞崲浜斿垎涓ゅ垎鍜屼竴鍒嗙殑紜甯侊紝姣忎竴縐嶆柟妗堢‖甯佹繪暟涓嶈兘瓚呰繃涓鐧炬灇錛岄棶鍑犵嶅厬鎹㈡柟妗
13縐嶃
1銆佹湁涓夌嶅艦寮忕殑C + +璇璦鏁存暟甯告暟錛鍗佽繘鍒錛屽叓鍜鍗佸叚榪涘埗銆
錛1錛夊嶮榪涘埗鏁存暟鏄鐢辨暟瀛0鑷9鐨勬暟鎹涓嶄互0寮濮嬨
錛2錛鍏榪涘埗鏁存暟鏄鏁板瓧0鍀7浠0寮濮嬬殑鏋勬垚鐨勬暟鎹銆
錛3錛夊嶮鍏榪涘埗鏁存暟鏄浠0鍙風殑緇勬垚鐨9涓鏁版嵁寮濮嬩互0x鎴0X鍜屽瓧姣嶄粠a鍒癴錛堝ぇ鍐欏拰灝忓啓瀛楁瘝錛夈
2銆佽緭鍏ユ槸涓涓姝f暣鏁n錛屾寚紺虹涓N涓鍙鑳界殑鏂規堥渶瑕佽緭鍑恆傝ユ柟妗堢殑欏哄簭鏄浠庡皯鍒板氱殑鎸変簲緹庡垎紜甯併
3銆佽緭鍑烘牸寮忥細
鏄劇ず鐨5緹庡垎錛2緹庡垎錛1緹庡垎錛岀涓n鏂規堢殑鏁伴噺銆傛瘡琛屾樉紺轟竴涓鏂規堬紝鐢錛屾渶鍚庝竴涓鏁板瓧鍚庨潰娌℃湁絀烘牸鐨勬暟瀛椾箣闂存湁涓涓絀烘牸銆
娉錛氬傛灉鏈夊皬浜巒鐨勬柟妗堬紝鎵鏈夊彲鑳界殑鏂規堝皢渚濇¤緭鍑恆
鎷撳睍璧勬枡;
1銆丆璇璦鏄涓縐嶉潰鍚戣繃紼嬬殑錛屾娊璞$殑涓鑸鐨緙栫▼璇璦錛屽畠琚騫挎硾搴旂敤浜庡簳鍙戝睍銆 C璇璦緙栬瘧鍜屼互綆鍗曠殑鏂瑰紡澶勭悊浣庣駭鍒鐨勫唴瀛樸 C璇璦鏄浜х敓浠鏈哄櫒璇璦灝戦噺騫跺彲浠ュ湪娌℃湁浠諱綍琛岄┒鐜澧冩敮鎸佽繍琛岀殑鏈夋晥緙栫▼璇璦銆傝櫧鐒禖璇璦鎻愪緵浜嗚稿氫綆綰у埆鐨勫勭悊鍔熻兘錛屼絾瀹冧粛鐒朵繚鎸佷簡璺ㄥ鉤鍙扮殑鐗規с傚啓鍦ㄦ爣鍑嗚勬牸鐨凜璇璦紼嬪簭涔熷彲浠ュ湪璁稿氳$畻鏈哄鉤鍙幫紝鍖呮嫭涓浜涙搷浣滃鉤鍙幫紝濡傚祵鍏ュ紡澶勭悊鍣ㄥ拰瓚呯駭璁$畻鏈榪涜岀紪璇戙
2銆佺幇鍦ㄦ渶鏂扮殑C璇璦鏍囧噯鏄疌18銆
3銆丆璇璦鏄涓縐嶉潰鍚戣繃紼嬬殑璁$畻鏈虹▼搴忚捐¤璦錛屽叾鏄浠庨潰鍚戝硅薄鐨勭紪紼嬭璦錛屽侰 ++錛孞ava鍜岀瓑涓嶅悓銆 C璇璦鐨勮捐$洰鏍囨槸鎻愪緵涓縐嶇紪紼嬭璦錛屽彲浠ヤ互綆鍗曠殑鏂瑰紡緙栬瘧鍜屽伐鑹轟綆綰у埆鐨勫唴瀛橈紝鍙鐢熶駭鏈哄櫒浠g爜騫惰繍琛屼竴涓灝忕殑閲忔病鏈変換浣曡繍琛岀幆澧冪殑鏀鎸併
4銆 C璇璦鎻忚堪鐨勯棶棰樺揩浜奼囩紪璇璦錛屼互杈冨皯鐨勫伐浣滈噺錛岃壇濂界殑鍙璇繪э紝瀹規槗璋冭瘯錛屼慨鏀瑰拰縐繪嶏紝鍜屼唬鐮佽川閲忕瓑鍚屼簬奼囩紪璇璦銆 C璇璦涓鑸鍙鏈10錛咃綖20錛咃紝姣旂敱奼囩紪璇璦浠g爜鎵浜х敓鐨勭洰鏍囩▼搴忕殑鏁堢巼浣庛傚洜姝わ紝C璇璦鍙浠ラ氳繃緙栧啓緋葷粺杞浠躲
5銆丆璇璦鏄涓縐嶉潰鍚戣繃紼嬬殑緙栬瘧璇璦銆傚叾榪愯岄熷害鏄闈炲父蹇鐨勶紝浠呮′簬奼囩紪璇璦銆 C璇璦鏄璁$畻鏈轟駭涓氱殑鏍稿績璇璦銆傛搷浣滅郴緇燂紝紜浠墮┍鍔ㄧ▼搴忥紝鍏抽敭閮ㄤ歡鍜屾暟鎹搴撴槸浠嶤璇璦涓嶅彲鍒嗙;濡傛灉涓嶅︿範C璇璦錛屼綘鍙浠ヤ笉鐞嗚В搴曞眰鐨勮$畻鏈恆
Ⅳ 硬幣兌換問題回溯法偽代碼
A數組用來存放硬幣,數值1代表正面,0代表反面;
static int s;s是存放每列狀態的數初始為0代表一列都沒翻,第幾位為1就代表第幾列被翻轉
int turncoin(A,S,N,n) //A(N*9數組) ,N是行數 n代表當次翻哪一列 初次調用n=0,代表第一列
{ int i=1;//因為每列只有兩種狀態,所以每列只翻一次
static int max=0;//用來存放翻轉後正面朝上的最大硬幣數;
static int S;//大S用來存儲當前硬幣堆的翻轉狀態
do {turncoin(A,S,N,n+1);if (n==8){ int tem=sum //sum為遍歷A數組,所有元素之和(即為當前正面朝上的硬幣數)
if(sum>max){S=s; //把當前翻轉狀態存儲到S,S內總是存儲著擁有正面朝上硬幣數量最高的一種翻轉狀態;}}}while(i--&&transform(N,n));
//transform()函數翻轉第N列的硬幣 並且對s的第n位置一 成功返回ture 並且對是 實現就是for(i=0;
i
拓展資料:
一、題目描述:
一個翻硬幣的游戲,有N(N <=10000)行硬幣,每行有九個硬幣,排成一個N*9的方陣,有的硬幣正面朝上,有的反面朝上。我們每次可把一整行或者一整列的所有硬幣翻過來,請問怎麼翻,使得正面朝上的硬幣盡量多(翻硬幣無次數限制)。
二、思路分析:
枚舉2^9種列的翻法。
遍歷N行,如果某行正面朝上的少,翻之;如果正面朝上的多,不翻
記下使得正面最多的方法即可
耗時O(2^9 * N)
這個得到的是最優解.用位運算效率還是很高的.
對每一列,都用一個9位的數表示,一共有N個
然後便利所有的9位狀態,(000000000)-(111111111) (二進制)
對於每個狀態,都與這N個數異或,每次異或後累加所有的1的值假設為k,如果k小於5則k=9-k.
對N個數累加所有的k,得到最終累加和.
求出所有狀態下累加和最大的,就是正面朝上的硬幣盡量多的個數.
翻面的方法橫列分別是最優解的8位狀態和與之對應的每個數異或後累加和k是否小於5.