聽說今天要上遞迴
[ Lecturer ]
"你這節課不是應該待在隔壁嗎"
"我英文手寫沒寫名字被扣 10 分"
"我有什麼辦法,就真的很可愛啊"
Repkironca,aka 阿蘇
你們應該知道我是誰吧
對吧對吧 (っ °Д °;)っ
bool IsLying (int first, int second){
if (first != 5 || second != 5){
cout << "My APCS successfully failed.\n";
return false;
}
cout << "stop lying, it's impossible for you\n";
return true;
}
這也是一個 function
而且它有傳入值跟回傳值
void Print (){
cout << "My APCS successfully failed.\n";
}
這是一個 function
這是 sin 的反元素
中文稱為 反正弦
但反弦 !=function
> 那可以在 function 中呼叫另一個 function 嗎
#include <iostream>
using namespace std;
void Study(){
cout << "Studying...\n";
}
void Touch_Ayame (){
cout << "Touching_ayame...\n";
}
void Compare (int study, int touch_ayame){
// 摸魚的英文不是 touch-fish,但摸余肯定是 touch-ayame
bool judge = study >= touch_ayame;
while(study > 0 || touch_ayame > 0){
if (study-- > 0) Study();
if (touch_ayame-- > 0) Touch_Ayame();
}
if (judge) cout << "好耶你真的是出來讀書的\n";
else cout << "你根本從頭到尾都在混==\n";
}
int main (){
int s, t; cin >> s >> t;
Compare(s, t);
}
問就是可以,有何不能的理由
study = 3
t.a. = 5
judge = false
study = 3
study = 2
t.a. = 4
study = 2
study = 1
t.a. = 3
study = 1
study = 0
t.a. = 2
t.a. = 2
t.a. = 1
t.a. = 1
t.a. = 0
"若有一函數是由自己定義的,則此為遞迴式"
[ 以數學角度來看 ]
這兩個東西是等價的!
int Fibonacci(int tar, int index = 2, int a = 1, int b = 0){
if (tar == 0) return 0;
// 如果是第 0 項,定義為 0
if (tar == 1) return 1;
// 如果是第 1 項,定義為 1
if (tar == index) return a + b;
// 若已經找到所求項,則 a + b 就是答案
return Fibonacci(tar, ++index, a+b, a);
// 否則更新 a、b,繼續找下一項
}
不要懷疑,我們剛剛怎麼呼喚別人
就怎麼呼喚自己,完全相同
一句話完成定義:在 function 中呼喚自己
[ 以資訊角度來看 ]
看起來很抽象ㄇ?那我們一步步抽絲剝繭
int Fibonacci(int tar, int index = 2, int a = 1, int b = 0){
if (tar == 0) return 0;
// 如果是第 0 項,定義為 0
if (tar == 1) return 1;
// 如果是第 1 項,定義為 1
if (tar == index) return a + b;
// 若已經找到所求項,則 a + b 就是答案
return Fibonacci(tar, ++index, a+b, a);
// 否則更新 a、b,繼續找下一項
}
tar = 5
index = 2
a = 1
b = 0
tar = 5
index = 3
a = 1
b = 1
tar = 5
index = 4
a = 2
b = 1
tar = 5
index = 5
a = 3
b = 2
tar = 5
index = 2
a = 1
b = 0
tar = 5
index = 2
a = 1
b = 0
tar = 5
index = 2
a = 1
b = 0
tar = 5
index = 3
a = 1
b = 1
tar = 5
index = 3
a = 1
b = 1
tar = 5
index = 3
a = 1
b = 1
tar = 5
index = 3
a = 1
b = 1
tar = 5
index = 4
a = 2
b = 1
tar = 5
index = 4
a = 2
b = 1
tar = 5
index = 4
a = 2
b = 1
tar = 5
index = 4
a = 2
b = 1
即第六行(二 & 四是特判)
一定要有個條件可以結束遞迴
且確保此條件是絕對會發生的
否則永遠跑不完
int Fibonacci(int tar, int index = 2, int a = 1, int b = 0){
if (tar == 0) return 0;
// 如果是第 0 項,定義為 0
if (tar == 1) return 1;
// 如果是第 1 項,定義為 1
if (tar == index) return a + b;
// 若已經找到所求項,則 a + b 就是答案
return Fibonacci(tar, ++index, a+b, a);
// 否則更新 a、b,繼續找下一項
}
int NeverStop(int n){
return NeverStop(n-1) + NeverStop(n-2);
}
缺乏終止條件
等同於無限迴圈
不是吃 TLE 就是被 RE
int NeverStop(int n){
if (n == 0) return 0;
return NeverStop(n-1) + NeverStop(n-2);
}
終止條件不合理
n = 1 時,會遞迴到 - 1
未考慮到所有情況
#include <iostream>
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
int F (int x){
if (x == 1) return 1;
if (x%2 == 0) return F(x/2);
return F(x-1) + F(x+1);
}
int main (){
gura // i/o 優化,不過這題不加也不會怎麼樣,與第二行等價
int num; cin >> num;
cout << F(num) << '\n';
}
還有其他雜七雜八的應用。
具體來說,遞迴 99.9 % 都不是用在剛剛那邊
CSES_2165 Tower of Hanoi
N = 1,總步數 1 步
N = 2,總步數 3 步
L M R
1
2
1
L M R
2
1
L M R
2
1
L M R
N = 3,總步數 7 步
2
L M R
1
3
2
L M R
1
3
2
L M R
1
3
2
L M R
1
3
2
L M R
1
3
2
L M R
1
3
2
L M R
1
3
"把上面所有東西移到暫存區,再把自己移到終點,最後把暫存區的東西放到終點"
int find_total (int num){
if (num == 1) return 1;
return 2 * find_total(num-1) + 1;
}
void move (int plate, int from, int mid, int tar){
if (plate == 0) return;
move(plate-1, from, tar, mid); //(上面的)起點 到 暫存
cout << from << ' ' << tar << '\n'; //(自己) 起點 到 終點
move(plate-1, mid, from, tar); //(上面的)暫存 到 終點
}
就,直接照做啊w
#include <bits/stdc++.h>
#define gura ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
int find_total (int num){
if (num == 1) return 1;
return find_total(num-1) * 2 + 1;
}
void move (int plate, int from, int mid, int tar){
if (plate == 0) return;
move(plate-1, from, tar, mid); //(上面的)起點 到 暫存
cout << from << ' ' << tar << '\n'; //(自己) 起點 到 終點
move(plate-1, mid, from, tar); //(上面的)暫存 到 終點
}
int main (){
gura
int plate_count; cin >> plate_count;
cout << find_total(plate_count) << '\n';
move(plate_count, 1, 2, 3);
}
很多東西寫成迴圈真的很難懂
當然如果你覺得迴圈比較好寫
你要用迴圈我也沒意見
只是後面題目真的很難砸迴圈
Solution:記憶化、砸演算法 ...
暫時還不用學會,我不打算也沒時間講
不過演算法小社會慢慢教
利用遞迴刻出輾轉相除法
希望你們還記得它┏(゜ロ゜;)┛
int gcd(int a, int b){
if (a < b) return gcd(b, a);
if (b == 0) return a;
return gcd(b, a % b);
}
喔你想多了,這當然不是 AC CODE
不過用遞迴做這題會被卡常
只能用迴圈就是
int binary_search (int tar, int l, int r, vector <int> vec){
int mid = (l+r) / 2;
if (vec[mid] == tar) return mid;
if (mid == l || mid == r) return 0;
if (vec[mid] > tar) return binary_search(tar, l, mid, vec);
return binary_search(tar, mid+1, r, vec);
}
//==========================
while (true){
int mid = (l+r) / 2;
if (vec[mid] == query){
cout << mid << '\n';
break;
}
else if (mid == l || mid == r){
cout << 0 << '\n';
break;
}
else if (vec[mid] > query) r = mid;
else l = mid + 1;
}
事實上用 BFS 也能解出
但我們還沒學資料結構
你們可能找不到方法做這個
否則滿水的其實
void dfs (int node){
visited[node] = true;
for (auto to:graph[node]){
if (!visited[to]) dfs(to);
}
}
其實就,輾轉相除法,一模一樣
很煩,超級煩,強烈建議用 vector 做
如果你做出了上一題,那這就是水題
已經有點實作題的味道ㄌ
八皇后問題,去年有被改編成社賽題目
做為防破台門檻。你們肯定可以的吧:)
前面的例題
理論上他希望你用遞迴刻 Merge Sort
但我知道你會砸 std::sort()
有個內建函式可以解決這個
但試試用遞迴寫 la
如果現在想不出來,可以等上完 DP 再回頭
相對來說比較簡單
前面的例題,且與 TCIRC_b001 完全等價
呈 CSES_2165,不過又多了變化
現在開始與結束狀態都不固定了
先思考一下他的遞迴式為何?
題目本身是不難
但輸出格式很麻煩
那就去看解答
沒啦,認真說的話,如果你已經苦思良久,完全沒有半點想法
去觀摩 AC CODE 從中汲取養分
並非什麼可恥之事,或你把任何想到的做法都砸一次
反正吃 WA 就吃 WA,又不會有人笑你
然後也可以在群組直接發問沒關係
只要有時間我們都很樂意幫助
真的不敢也可以來私訊我 XD
有人簡稱為 二二八
可惜他不會打橄欖球
有人簡稱為 二和
可惜不是北一的那間
不是 那真的很好吃 我確定
現在就可以繳錢了,快來吧
建中社活組是個破單位咩