# S3 演算法 week 6 ###### tags: `S3 公開資源` :::info 時間:12/25 9:00 ~ 17:00 地點:成大資工系新館 **65304** 教室 主題:遞迴與排序 直播連結:https://youtu.be/boxEzGdyuiQ ::: # 必作題題解 [TOC] ## 二章-第六節 ### [No-Judge 能撐多久](https://hackmd.io/@sa072686/cp/%2FFRgcCDGCQG-ECiVj7tWSgw#%E8%83%BD%E6%92%90%E5%A4%9A%E4%B9%85) 撰寫者:fishhh $$ f(n) = \begin{cases} 0 & n = 0 \\ f(\lfloor \frac{n}{b} \rfloor) + 1 & n > 0 \end{cases} $$ :::spoiler 參考程式碼 ```cpp #include "iostream" using namespace std; int a,b; int top_down(int now){ if(now==0){ return 0; } return top_down(now/b)+1; } int top_down2(int now){ if(now>a){ return 0; } return top_down2(now*b)+1; } int main(){ cin>>a>>b; cout<<top_down(a)<<"\n"; cout<<top_down2(1)<<"\n"; //buttom up int cnt=0; while(a!=0){ a/=b; cnt++; } cout<<cnt<<"\n"; } ``` ::: --- ### [No Judge - 次方加總](https://hackmd.io/@sa072686/cp/%2FFRgcCDGCQG-ECiVj7tWSgw#%E6%AC%A1%E6%96%B9%E5%8A%A0%E7%B8%BD) 撰寫者:fishhh $$ f(n) = \begin{cases} 1 & n = 1 \\ f(n - 1) \times n + 1 & \text{otherwise} \end{cases} $$ :::spoiler ```cpp= #include "iostream" using namespace std; int a,b; int top_down(int now){ if(now==0){ return 1; } return top_down(now-1)*a+1; } int n_pow; int top_down2(int now){ //或者是回傳型別改成pair<int,int> 會更直觀(補充) if(now==0){ n_pow=1; return 1; } int ret=top_down2(now-1); n_pow*=a; return ret+n_pow; } int main(){ cin>>a>>b; cout<<top_down(b)<<"\n"; cout<<top_down2(b)<<"\n"; //buttom_up int now=1,ans=0; for(int i=0;i<=b;i++){ ans+=now; now*=a; } cout<<ans<<"\n"; } ``` ::: --- ### [No Judge - 擲骰](https://hackmd.io/@sa072686/cp/%2FFRgcCDGCQG-ECiVj7tWSgw#%E6%93%B2%E9%AA%B0) $$ f(n, m) = \begin{cases} \displaystyle\sum_{k = 1}^{b}f(n - 1, m - k) & n > 0 \\ 1 & m = 0 \\ 0 & \text{otherwise} \end{cases} \\ ans = f(a, c) $$ 撰寫者:fishhh :::spoiler 參考程式碼 ```cpp= #include "iostream" using namespace std; int a,b,c; int top_down(int now_dice,int tot){ if(now_dice==0){ if(tot==c)return 1; else return 0; } int cnt=0; for(int i=1;i<=b;i++){ cnt+=top_down(now_dice-1,tot+i); } return cnt; } int main(){ cin>>a>>b>>c; cout<<top_down(a,0)<<"\n"; /*******以下為 bottom up 解法*******/ int count[10][200]={}; //count[i][j] 前i顆骰子 可以丟出幾次總合為 j 的情況 //因為題目給沒有給範圍 這裡假設最多9顆骰子 count[0][0]=1; for(int i=1;i<=a;i++){ for(int j=0;j<=100;j++){ //假設 a*b max =100 for(int k=1;k<=b;k++){ count[i][j+k]+=count[i-1][j]; } } } cout<<count[a][c]; } ``` ::: --- ### [No Judge - 比較大小](https://hackmd.io/@sa072686/cp/%2FFRgcCDGCQG-ECiVj7tWSgw#比較大小) 撰寫者:Eason ~~雖然可以直接比較兩個字串~~ 但請大家使用遞迴去練習 用遞迴去比較每一個字元 需特別注意當$s_i$ = $t_i$時 要判斷應該回傳還是繼續遞迴 其他情況回傳題目所要求的即可 :::spoiler 參考程式碼 ```cpp= #include<iostream> using namespace std; long long s_len, t_len; int cmp(string a, string b, int index){ if (a[index] < b[index]) return -1; else if (a[index] > b[index]) return 1; else if (a[index] == b[index] && index == s_len - 1 && s_len == t_len){ return 0; } else return cmp (a, b, index + 1); } int main(){ string s, t; cin >> s >> t; s_len = s.size(); t_len = t.size(); cout << cmp (s, t, 0) << '\n'; return 0; } ``` ::: --- ### [No - Judge 爬樓梯問題](https://hackmd.io/@sa072686/cp/%2FBbRsMnLrQFuCeLifVxecJA#爬樓梯問題) 撰寫者:Eason 我們假設 $dp_i$ 為爬上第 $i$ 階的方法數 則可以先算出: >第 $1$ 階($dp_1$) = 1 (因為只能從第0階走上來) >第 $2$ 階($dp_2$) = 2 (可以從第0階走兩步上來,也可以從第1階走一步上來) >第 $i$ 階($dp_i$) = $dp_{i-1} + dp_{i-2}$ (可以從第$i-2$階走兩步上來,也可以從第$i-1$階走一步上來) $$ dp_i = \begin{cases} 1 & i = 1 \\ 2 & i = 2 \\ dp_{i-1} + dp_{i-2} & \text{otherwise} \end{cases} $$ 所以直接用陣列模擬就好 :::spoiler bottom-up ```cpp= #include<iostream> using namespace std; int main(){ int n; cin >> n; long long dp[105]; dp[1] = 1; dp[2] = 2; for (int i = 3; i <= n; i++){ dp[i] = dp[i - 1] + dp[i - 2]; } cout << dp[n] << '\n'; return 0; } ``` ::: :::spoiler top-down ```cpp= #include<iostream> using namespace std; long long solve(int i){ if (i == 1) return 1; else if (i == 2) return 2; return solve(i - 1) + solve(i - 2); } int main(){ ios::sync_with_stdio(0), cin.tie(0); int n; cin >> n; cout << solve(n) << '\n'; return 0; } ``` ::: --- ### [No-Judge 爬樓梯.改一](https://hackmd.io/@sa072686/cp/%2FBbRsMnLrQFuCeLifVxecJA#%E7%88%AC%E6%A8%93%E6%A2%AF%EF%BC%8E%E6%94%B9%E4%BA%8C) 撰寫者:fishhh :::spoiler 參考程式碼 ```cpp= #include "iostream" using namespace std; int step[100]={}; int top_down(int now){ if(now<=0){ return 0; } return min(top_down(now-1),top_down(now-2))+step[now]; } int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ cin>>step[i]; } cout<<top_down(n)<<"\n"; /*~~~~~~~~~~buttom-up~~~~~~~~~~~~~*/ int min_cost[100]={}; // min_cost[i] 代表位於 i 時的最小扣血量 for(int i=1;i<100;i++)min_cost[i]=1e9; //min_cost[0] 一定是0 (因為是起點) for(int i=0;i<=n;i++){ // 枚舉起點 min_cost[i+1]=min(min_cost[i+1],min_cost[i]+step[i+1]); min_cost[i+2]=min(min_cost[i+2],min_cost[i]+step[i+2]); } cout<<min_cost[n]<<"\n"; } ``` ::: --- ### [No - Judge 爬樓梯.改二](https://hackmd.io/@sa072686/cp/%2FBbRsMnLrQFuCeLifVxecJA#爬樓梯.改二) 撰寫者:Eason 大致概念跟爬樓梯問題一樣 改一下初始的值就好 $$ dp_i = \begin{cases} 1 & i = 1 \\ 1 & i = 2 \\ 2 & i = 3 \\ 4 & i = 4 \\ dp_{i-1} + dp_{i-3} + dp_{i-4} & \text{otherwise} \end{cases} $$ :::spoiler bottom-up ```cpp= #include<iostream> using namespace std; int main(){ int n; cin >> n; long long dp[105]; dp[1] = 1; dp[2] = 1; dp[3] = 2; dp[4] = 4; for (int i = 5; i <= n; i++){ dp[i] = dp[i - 1] + dp[i - 3] + dp[i - 4]; } cout << dp[n] << '\n'; return 0; } ``` ::: :::spoiler top-down ```cpp= #include<iostream> using namespace std; long long solve(int i){ if (i == 1) return 1; else if (i == 2) return 1; else if (i == 3) return 2; else if (i == 4) return 4; return solve(i - 1) + solve(i - 3) + solve(i - 4); } int main(){ ios::sync_with_stdio(0), cin.tie(0); int n; cin >> n; cout << solve(n) << '\n'; return 0; } ``` ::: --- ### [No-Judge 運算式求解](https://hackmd.io/@sa072686/cp/%2FBbRsMnLrQFuCeLifVxecJA#%E9%81%8B%E7%AE%97%E5%BC%8F%E6%B1%82%E8%A7%A31) 撰寫者:fishhh