2. 例題
2.2 遞迴
遞推強調當前狀態與前乙個狀態的關係,一種考察類似動態規劃的思維處理,另一種考察思維:當前狀態確定後,後繼的所有狀態全部確定。
遞迴的處理思路就算當前狀態取決於子狀態的情況,求當前狀態需要先計算出子狀態後才能決定。
2.1.1 思維遞推
acwing95費解的開關
題意:25盞燈排成乙個5x5的方形。每乙個燈都有乙個開關,遊戲者可以改變它的狀態。每一步,遊戲者可以改變某乙個燈的狀態。遊戲者改變乙個燈的狀態會產生連鎖反應:和這個燈上下左右相鄰的燈也要相應地改變其狀態。用數字「1」表示一盞開著的燈,用數字「0」表示關著的燈。給定n次遊戲的初始狀態,編寫程式判斷遊戲者是否可能在6步以內使所有的燈都變亮。∑
n\sum_{}n
∑n<= 500
題解:通過分析可以知道當前行的狀態取決於下一行的按燈方式,而下一行的按燈方式卻決於當前行的狀態。也就是說一旦當前行的狀態確定了,下一行怎麼按燈也決定了,往後遞推,那麼所有燈的狀態也決定了。因此,只需要遍歷第一行可能出現的情況,然後就可以發現所有的狀態,然後判斷第5行是否全為1即可。
**:
#include
using
namespace std;
int dx=
, dy=
;int n;
char g[10]
[10], backup[10]
[10];
// 模擬按鍵
void turn (
int x,
int y )
return;}
intmain()
}// 判斷最後一行是否全為1
bool is_success =
true
;for
(int i =
0; i <5;
++i)
if(g[4]
[i]==
'0')
// 全為1,則更新答案
if(is_success) ans =
min(ans, step)
;memcpy
(g, backup,
sizeof backup);}
if(ans <=
6) cout << ans << endl;
else cout <<-1
<< endl;
}return0;
}
codeforces round #658 (div. 2) b. sequential nim
題意:兩個人玩博弈論遊戲,有許多堆石頭,每堆石頭的數目都大於等於1,每次只能從第一堆石頭取,可以取任意個正整數的石頭,一旦不能取石頭那麼就輸了。一開始第乙個人先取,如果第乙個人最後能贏,輸出first;如果第二個人最後能贏,輸出second。∑
n\sum_{}n
∑n<= 105
題解:如果當前石頭數大於1,那麼當前這個人可以選擇是否交換先後手;如果當前石頭數字1,那麼當前這個人必須交換先後手。因此,一旦出現第乙個大於n的石頭數目,當前這個人就可以根據後面的石頭數,找到最優策略,然後取勝(當前如果是k>1,那麼可以根據後面的石頭確定一種獲勝狀態),因此只需要計算出現第乙個大於1的石頭前面1的個數,如果是奇數,那麼second,否則first(奇數說明到second拿這堆石頭);如果全為1,那麼奇數個1輸出first,否則second(奇數說明一直交換先後手,然後又回到first)
**
#include
using
namespace std;
intconst n =
2e5+10;
int t, a[n]
;int n;
intmain()
return0;
}
2.2.4 思維最小步數
acwing1208. 翻硬幣
題意:一開始給定兩個字串a和b,字串由』*'和』o』組成。每次變化可以將相鄰的兩個字元同時變化(*->0, 0->*),問最少多少次變化可以將a變成b?字串a、b的長度均小於等於100.
題解:題目咋一看是最小步數模型,但是n能到達100,bfs最小步數必然超時。考慮每次變化的關係:每次變化將相鄰的兩個字元反轉,相當於異或操作。對於異或操作來說,異或奇數次可以規約到1次,異或偶數次可以規約到0次,同時異或沒有先後順序之分。因此,對於所有的變化來說,相當於有n個開關,每個開關控制a[i]和a[i+1]。每個開關只有按和不按兩種情況,要求最小的步數,只需要奇數次都規約到1次,偶數次都規約到0次,然後按下的開關是必須的即可。因此,從前往後掃瞄,如果a[i]!=b[i],那麼需要按下開關i,然後把a[i]和a[i+1]反轉,這樣每次按下都是必須的,也就是最少的步數。
**:
#include
using
namespace std;
string s, e;
void
turn
(int x)
intmain()
cout << res << endl;
return0;
}
2.1.2 dp類遞推acwing 92遞迴實現指數型列舉
題意:從 1 ~ n 這 n 個整數中隨機選取任意多個,輸出所有可能的選擇方案。1 ≤ n ≤ 15
題解:n只有15,使用二進位制表示每個數字是否被選即可
**:
#include
using
namespace std;
int n;
void
dfs(
int cur,
int num)
cout << endl;
return;}
dfs(cur +
1, num <<1)
;dfs
(cur +
1, num <<1|
1);return;}
intmain()
遞推與遞迴
遞推與遞迴 遞推像是多公尺諾骨牌,遞迴是大事化小。遞推的效率更高 遞推 斐波那契數列 例 母親為兒子的四年大學學費準備了一筆存款,兒子每月月底取下月生活費1000元。銀行年利率為 1.71 畢業時連本帶息要取出 1000 元。則要存入多少錢。include define rate 0.0171 in...
遞推與遞迴
遞迴 將問題規模為n的問題,降解成若干個規模為n 1的問題,依次降解,直到問題規模可求,求出低階規模的解,代入高階問題中,直至求出規模為n的問題的解。遞推 構造低階的規模 如規模為i,一般i 0 的問題,並求出解,推導出問題規模為i 1的問題以及解,依次推到規模為n的問題。遞迴包括回溯和遞推兩個過程...
遞迴與遞推
1 遞迴與遞推的定義 前者是 後者是對以前的問題進行計算,以得出當前問題的大結果。2 它們的典例和運用遞迴 遞推dfs,搜尋與回溯 動態規劃 用遞推能做的,記憶化搜尋定能夠實現 遞推僅能求方案數,求具體方案需用遞迴 3 各種關於遞推的例題 爬樓梯 數樓梯 兔子問題 includeusing name...