暑假資讀[0]

從0開始的異世界生活程式人生

講師

  • (1.5)25賴柏宇
  • 海之音、Sea_of_Voices、小海或其他類似的
  • 美術能力要完蛋了
  • 表達能力差,聽不懂請馬上舉手問
  • INFOR 36th 學術長
  • 學弟加資訊社
Index
  • C++簡介
  • 怎麼寫程式
  • Hello, world!
  • 變數
  • I/O
  • 運算子
  • 陣列
  • 指標/參考
  • 條件式
  • 迴圈
  • 函式 / 遞迴
  • 物件
  • OJ
  • Contests

:你知道電研花了一個半小時的小社就把這堆東西講完了嗎

:那當然 那可是BrineTW我的偶像欸

C++簡介

說真的 我相信你們都比我清楚

從C開始
  • 一種中階語言
  • 組合語言 -> C語言
  • 許多高階語言的基礎
  • 你可以叫C爸爸
  • 編譯型語言
  • 運行速度極快
  • 物件導向(OOP)
  • 強類型、靜態
從C開始

機器碼

程式語言發展

組合語言

C

0000 0000 000000010000
0000 0001 000000000001
0001 0001 000000010000
0001 0001 000000000001
     section .data
 msg     db      'Hello, world!',0xA
 len     equ     $-msg
 
     section .text
 global  _start
 _start:
         mov     edx,len
         mov     ecx,msg
         mov     ebx,1
         mov     eax,4
         int     0x80
 
         mov     ebx,0
         mov     eax,1
         int     0x80
#include<stdio.h>
int main(){
    printf("Hello, world\n");
    return 0;
}

(亂找的 這不是Hello world)

低階 -> 高階

不是給人看 -> 給人看的

所以別再抱怨C/C++很難讀懂了

從C開始

C

C

#include<stdio.h>
int main(){
    printf("Hello, world\n");
    return 0;
}
#include<iostream>
int main(){
    std::cout << "Hello, world" << std::endl;
    return 0;
}

C++

Python

print("Hello, world\n")

Java

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("hello, world!");
    }
}
從C開始

C/C++

C

C++

Python

C/C++的運作

組語

編譯

機器碼

組譯

C++
  • 加了不少擴充的C
  • 基本上是C的向上兼容
  • 更加物件導向(OOP)
  • 終於不用什麼都自己寫了(淚
  • 運行速度和C差不多
  • STL我的神

怎麼寫程式

其實這原本應該是807⁸⁰⁷要講但他不在 部分簡報by 807⁸⁰⁷

IDE(整合式開發環境)
  • 好用、方便、功能多
  • 語法凸顯、各種外掛套件
  • 文字編輯器、編譯器、除錯器等
  • 專案開發常用,常針對特定語言
  • (本機) Visual Studio (Microsoft), Code::Blocks, DEV-C++,
  • 難裝、吃很多資源
VScode(文字編輯器)
  • 打題目時更好用
  • 自己裝編譯器
  • 各種無敵外掛插件
  • 字很好看
  • 字很好看,真的
  • 提示字用起來很方便,用過回不去其他的
VScode
  • 搜尋VScode
  • 安裝Windows版
  • 不要用電教電腦的VScode寫C++,很怪
  • 插件裝Code Runner, C++
  • 設定裡有很多酷東西,可以自己摸看看
  • 在設定裡把Run in terminal勾起來
編譯器(MSYS2)

1. 前往 msys2 並下載  window7或以前請自求多福
2. 不要改路徑              除非你能背起來
3. 繼續 繼續 完成
4. 開啟msys2
5. 輸入

 


如果有詢問輸入  Y

 

pacman -S mingw-w64-ucrt-x86_64-gcc
編譯器(MSYS2)

6. 前往環境變數(可以用左下角的搜尋)
7. 選取 系統變數 中的 Path 然後按下 編輯
8. 按 新增 然後貼上這段路徑

 

如果有如果有變更路徑: 去資料夾找 你改的路徑+\ucrt\bin

9. 確定 確定 確定

C:\msys2\ucrt64\bin
編譯器(MSYS2)

記得重開 VSCODE

編譯器(MSYS2)

1. 按 Ctrl+` 開啟終端機

2. 輸入

 

    出現👇代表安裝成功

 

g++ --version
g++ (Rev10, Built by MSYS2 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

偷偷介紹WSL

其實這原本應該是807不該講但他不在 簡報by807

WSL(Linux子系統)

Windows Subsystem for Linux

 

超好用的東西

WSL(Linux子系統)

按Windows+R 輸入 cmd(開啟cmd)

輸入

按Windows+R 輸入 wsl(開啟wsl)

輸入

 

wsl --install
sudo apt upgrade
sudo apt install g++ gdb
code .

更新apt

安裝編譯器

開啟vscode

WSL(Linux子系統)

安裝好了!

比剛剛快多了

 

Hello, world!

第一次接觸某程式的傳統

做就對了
  • 開啟一個新檔案叫hello_world.cpp
  • 輸入以下程式
  • 按下Ctrl + Alt + N,沒意外的話會顯示hello, world
#include<iostream>
int main(){
    std::cout << "hello, world\n";
    return 0;
}
  • 沒帶筆電就乖乖用Code::Blocks吧 或者你可以用Replit

Code::Blocks

VScode

程式架構
  • 預處理:有#開頭的東西
  • 編譯:將預處理完的程式編譯成組語
  • 執行:程式的會直接從int main()開始執行,所以等等要寫的東西除非特別註明,都丟在main(){}裡
  • 每行程式用分號分開
#include<iostream>
#define io std::ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
/*

可能有其他函式、結構變數

*/
int main(){
    io;
    std::cout << "hello, world\n";
    return 0;
}

<-預處理

<-其他函式區

<-主函式區

變數/Variable

Variable: 多變的 那const變數怎麼解釋

變數
  • 電腦裡的一段記憶體,可用於儲存資料
  • C++是靜態型態,強型別,所以宣告任何變數都要講清楚類別(部分情況除外)
  • 通常型別不能任意轉換
  • int (整數) / unsigned int (無號數,只能存正值)
  • long long(長整數) / unsigned long long
  • float (浮點數/小數)
  • double (倍精度浮點數)
  • short / unsigned short

int占4 bytes(32位元) -> 儲存範圍

(一格存正負,剩下存數字),以此類推 unsigned int 存

long long 占 8 bytes,範圍

float占 4 bytes,範圍 3.4E +/- 38 (7 位數)

double占 8 bytes,範圍 1.7E +/- 308 (15位數)

short占 2 bytes,範圍

[-2^{31},\ 2^{31})
[0,\ 2^{32})
[-2^{63},\ 2^{63})
[-2^{15},\ 2^{15})
其他型別
  • char / unsigned char / signed char 字元
  • bool (布林值) (false/true)
  • string 字串<- 這東西嚴格說來不算是變數

char是以ASCII編碼,實際字元作用的範圍只有0~127,但可以存-128~127(或0~255)

當整數被轉成bool時,只有0是false,剩下數字都是true,bool轉成整數時預設是0和1

string在C裡面是字元陣列(後面會提),在C++裡我們有現成的string可以用,等等提

宣告與使用變數
  • 申請空間
  • 宣告方式:型別名稱 變數名1, 變數名2;
  • 例如 int a, b;
  • =:將右值複製存到左邊
  • 也可以在宣告時一併賦值,如 int a=5;
  • char的賦值要加 ' ',string的賦值要加" "
  • char因為本身也是數字,所以要用整數賦值也不是不行,之後會遇到
string
  • 程式新手最大問題 吧
  • 不要和字元搞混,字串是一堆字元串在一起
  • 記得加 " "  記得加 " " 記得加 " "
  • 使用前先 #include<string> 或 #include<bits/stdc++.h>
  • using namespace std;或using std::string;
string
  • string objectA = "Apple", objectB = "Banana";
  • objectA+objectB會是"AppleBanana" (字串加法)
  • 如果想要取得 string 的長度,可以把 .size() 放在一個 string 後面
跳脫字元
  • \ 加上某個字,用在字元或字串裡
  • 常用跳脫字元:
  • \n 換行,很重要,無限顆星號
  • \b backspace(刪除一格)
  • \t tab
  • \0 空字元(用於c-style string)的結尾
  • \\ 反斜線 (跳脫 跳脫字元.jpg)
  • \' 單引號 (防止出現 char a = ''';這種詭異情況)
  • \" 雙引號 (同上)
作用域
  • 變數的作用範圍
  • 全域變數:宣告在各個函式之外的變數
  • 區域變數:宣告在「某組大括號」之內的變數
  • 區域變數的作用範圍是宣告底下,到最近的右大括號
  • 生命週期:區域變數在程式執行到右大括號時死亡
  • 當全域和區域變數撞名時,總是優先使用區域變數
int a = 1; //外層變數
{
    int a = 2; //內層變數
}
a = 3;//到這裡{}裡的a就沒有作用了,修改的是外層的那個
修飾字
  • 讓變數具備某些特性
  • 宣告:修飾字 變數型態 變數名稱;
  • const:常量,不可修改
  • static:靜態變數,生命週期一直到程式結束
  • extern

I/O

實際上我更愛scanf/printf

輸出
  • #include <iostream>
  • using namespace std;
  • cout << 變數1 << 變數2 << 變數3....; 也可以是字串,例如 cout << "hello, world\n" << 變數1;
  • 小試身手
  • string apple = "banana";
  • cout << "apple" << ' ' << apple;
輸入
  • 從終端機取得值存到變數
  • cin >> 變數1 >> 變數2 >> 變數3;
  • 輸入以空白字元隔開,包括space,換行等
  • 一次取一行:getline(cin, stringName);
  • 一次取一個字元:c = getchar();
優點與缺點
  • 自動判斷變數型別
  • 直觀,好寫
  • 優化:加上
  • 犧牲混用性(不能用printf scanf)與在線性換來速度
  • <<和>>在大量時超醜
std::ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); 
C-style Output
  • #include <stdio.h>
  • printf(const char*(常量字串), 變數1, 變數2...);
  • %○代表此位置替換成變數內容
    • %d: 十進位 int
    • %u: unsigned int
    • %lld: long long
    • %c字元
    • %s C-style string
    • %f 浮點數
    • %e 科學記號浮點數
    • %p 指標
int a=3, b=5;
printf("%d %d", a, b);
int a=5;
printf("%p", &a);
C-style Output
  • #include <stdio.h>
  • scanf(const char*, 變數指標1, 變數指標2...);
  • %與printf同理
  • 格式化輸入輸出好用
  • 壓常可以用,雖然top coder都用快讀快寫
int hr, min;
scanf("%d:%d", &hr, &min);
int a, b;
scanf("%2d%2d", &a, &b);
#include <iostream>
int main(){
    int a, b;
    cin >> a >> b;
    cout << a << ' ' << b << '\n';
    return 0;
}
#include <stdio.h>
int main(){
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d %d", a, b);
    return 0;
}
EOF
  • 有時題目會要求吃到檔案結尾(end of file, eof)就結束輸入
  • while(cin >> a)
  • if(cin.eof()) break;
  • while(scanf("%d", &a) != EOF)

運算子(operator)

畢竟電腦是電子計算機,會運算是很正常的

運算子
  • 利用變數做計算的方式
  • 善用()提高可讀性,也可以減少錯誤
  • 一般運算
  • +加
  • -減
  • *乘
  • /除
  • %取餘數
  • 位元運算
  • >>右移
  • <<左移
  • ~補數(一元)
  • &bit and
  • | bit or
  • ^ bit xor
  • 邏輯/比較運算(回傳布林)
  • >大於
  • >=大於等於
  • <小於
  • <=小於等於
  • ==等於
  • !=不等於
  • &&邏輯且
  • ||邏輯或
  • !非(一元)
運算子
  • ++/--
  • 放在變數前面:變數+1/-1然後再進行運算
  • 放在變數後面:先進行運算再+1/-1
  • +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=
  • a X= b; 等價於 a = a X b;

優先順序:先乘除後加減,然後是位元運算和邏輯運算

不確定時括號是你的超人

ZJ a002

ZJ a003

TIOJ 1002

ZJ a065

ZJ a263 (EOF 不會用可以和我講 我幫你寫)

陣列

用Vector啦

一維陣列
  • 一連串相同型態的變數,在電腦中是一段連續的記憶體
  • 同一型態變數 輸入量不固定/大量 時使用
  • 宣告:變數型態 陣列名稱[陣列大小];
  • 初始化:使用大括號包起來,逗號分開元素
  • 全域陣列的大小只能是常數
一維陣列
  • 取値:利用 陣列名稱[索引值] 存取單一格元素
  • 索引值是從0開始到陣列大小-1,別耍笨(重要)
  • int a[5]; a[0] = 48763; cout << a[0]; //48763
高維陣列
  • 如果剛剛的一維陣列是一條數線,二維陣列就是笛卡兒平面,以此類推
  • n維陣列是n-1維陣列的陣列

data[0]

data[1]

data[2]

data[3]

data[4]

一維陣列data[5]

data[0][0]

data[1][0]

data[2][0]

data[3][0]

data[4][0]

data[0][1]

data[1][1]

data[2][1]

data[3][1]

data[4][1]

data[0][2]

data[1][2]

data[2][2]

data[3][2]

data[4][2]

二維陣列data[5][3]

高維陣列
  • 抽象化後只要把高維陣列當成有多個索引值供查詢的資料容器就好
  • 使用方式和一維陣列幾乎相同
  • 宣告
  • 變數型態 陣列名稱[第一維大小][第二維大小]...;
  • int data[5][3][2];就是宣告一個大小為5*3*2的三維陣列
(C-style)string
  • 字元陣列,以空字元結尾
  • char a[] = "apple";  實際大小是6
  • { 'a', 'p', 'p', 'l', 'e', '\0' }
  • 因為是陣列,可以用[]取特定位置的字元
  • C++的string也可以用[]取

指標(和參考)

老實說指標沒很常用 我都用參考

指標(pointer)
  • 一種變數,儲存記憶體的位置
  • 也可指稱某記憶體位置
  • 可以拿來申請空間
  • 占 8 byte ,同 long long
  • 直接看code
指標(pointer)
  • 宣告:變數型別 *變數1, *變數2...;
  • 取一個變數的位址:&變數
  • 存取某位址的內容:*指標
  • 宣告新指標(申請空間):new 變數型態;
#include<iostream>
using namespace std;
int main(){

    int *a = new int;
    cout << a << '\n'; //0xbe1560

    int b = 5;
    int *c = &b;
    cout << c << ' ' << *c; //0x70fdfc 5
    return 0;
}
指標(pointer)
  • 空指標:nullptr
  • 刪除變數(釋放空間):delete 指標;
  • 陣列本身也是指標
  • data[index] 相當於 *(data+index)

data[0]

data[1]

data[2]

data[3]

data[4]

類似變數存取

data

data+1

data+2

data+3

data+4

指標

&data[0]

&data[1]

&data[2]

&data[3]

&data[4]

相當於

指標(pointer)
  • 高維陣列:指向指標的指標
#include<iostream>
using namespace std;
int main(){
    int data[5][5];
    for(int i=0;i<5;i++){
        for(int j=0;j<5;j++){
            data[i][j]=i*5+j;
        }
    }
    /*
    {
        { 0,  1,  2,  3,  4},
        { 5,  6,  7,  8,  9},
        {10, 11, 12, 13, 14},
        {15, 16, 17, 18, 19},
        {20, 21, 22, 23, 24}
    }
    */
    cout << *(*(data+2)+3); //13
    return 0;
}
指標(pointer)
  • 高維陣列:指向指標的指標
  • 註:取址/取值運算子優先順序高於五則運算

*data

*(*(data+1)) : 5 *(*(data+1)+1):6 *(*(data+1)+2):7 *(*(data+1)+3):8 *(*(data+1)+4):9

*(data+1)

*(*data) : 0 *((*data)+1) : 1 *((*data)+2) : 2 *((*data)+3) : 3 *((*data)+3) : 4

...

參考(reference)
  • 變數的別名
  • 直接看code
#include <iostream>
using namespace std;
int main() {
    int a = 5;
    int &b = a;
    b = 1;
    cout << a; //1
    return 0;
}
  • 修改b(參考)時也會修改到a(變數)
參考(reference)
  • 加上 cout << &a << ' ' << &b; 確認
  • output: 0xf6b7ffd24 0xf6b7ffd24
  • 共用相同記憶體!
  • 宣告: 變數型態 &參考名 = 變數;
  • 注意必須有初始值
  • 一旦宣告,指稱的對象就不能被修改
  • C++專有語法,C裡沒有
  • 底層應該是用pointer實作的

條件式

if - else 應該不會有人特別去用 switch - case 啦

if-else
  • 流程圖 & 語法
  • contition: bool
// do something

if(condition){
    // do something if true
}
else{
    // do something if false
}

// do something
  • else可無
if-else
  • 多層條件和多個結果
  • 巢狀結構和else if
// ...

if(condition1){
    //...
}
else{
   if(condition2){
       // ...
   }
   else{
       // ...
   }
}

// ...
// ...

if(condition1){
    // ...
}
else if(condition2){
    // ...
}
else{
    // ...
}

// ...
三元運算子
  • 條件?成立時回傳值:不成立時回傳值
  • 後兩者的型態必須相同
  • 將a的絕對值存到b
  • 速度比if - else快一些
b=a>0?a:(-a);

迴圈(loops)

while loops
  • 做重複或類似的的事情
  • 持續條件很重要
  • 輸入到EOF的運作原理
// ...
while(condition){
    // ...
}
// ...
// ...
while(cin >> n){
    // ...
}
// ...
for loops
  • 和while類似,只是把初始化、持續條件、常駐步驟寫在一起(三個都可以選擇不填)
// ...
for(初始化; 持續條件; 常駐步驟){
    // ...
}
// ...
  • 固定執行n次
// ...
for(int i=0; i<n; i++){
    // ...
}
// ...
無窮迴圈
  • 不終止的迴圈,條件永遠都是true
while(true){
    // ...
}
  • 如何跳出這種迴圈?
break, continue
  • 中斷迴圈
  • break:直接跳出迴圈外
  • continue:強制回到迴圈頭(執行判斷等)
//範例:如果輸入=0就跳出
int n;
while(true){
    cin >> n;
    if(n==0) break;
    // ...
}
//也可以寫成
int n;
while(cin >> n && n!=0){
    // ...
}
//範例:輸出輸入的數字
//除非輸入=48763則跳過
int n;
while(true){
    cin >> n;
    if(n==48763) continue;
    cout << n << '\n';
    // ...
}
多層迴圈
  • 在迴圈裡跑迴圈
  • 怎麼跳出多層迴圈?
#include<iostream>
using namespace std;
int main(){
    int data[5][5];
    for(int i=0;i<5;i++){
        for(int j=0;j<5;j++){
            data[i][j]=i*5+j;
        }
    }
    /*
    {
        { 0,  1,  2,  3,  4},
        { 5,  6,  7,  8,  9},
        {10, 11, 12, 13, 14},
        {15, 16, 17, 18, 19},
        {20, 21, 22, 23, 24}
    }
    */
    cout << *(*(data+2)+3); //13
    return 0;
}

重新看一次這份code,應該要能知道為什麼結果是這樣

do while
  • 很少用到
  • 先做一次再判斷條件
do{
    // ...
} while(condition);
遍歷陣列(C++11以上)
  • 好用
  • 可搭配auto讓編譯器自動判斷型別
int a[]={0, 1, 2, 3, 4};
for(int i:a) i=0;
for(int i:a) cout << i << ' '; // 0, 1, 2, 3, 4

將陣列內的值分別複製到 i 中,然後跑過a陣列

注意如果是在多維陣列裡,因為陣列就是指標,所以如果修改低維的內容還是會改到值

int a[]={0, 1, 2, 3, 4};
for(int& i:a) i=0;
for(int i:a) cout << i << ' '; // 0, 0, 0, 0, 0

i 的參考分別指向 i[0], i[1]..., i[4]

ZJ a149

ZJ a015

ZJ a010

ZJ a022

ZJ a009

ZJ a024 (數學)

TIOJ 1007 (數學)

逆向 ZJ b515 (英文轉摩斯密碼)

TIOJ 1007 參考解答

#include <iostream>
#define int unsigned long long
using namespace std;
signed main() {
    int n, m;
    cin >> n >> m;
    int dp[n + 1];
    for (int i = 0; i <= n; i++) dp[i] = 0;
    dp[0] = 1;
    dp[1] = 1;
    int temp;
    for (int l = 1; l < m; l++) {
        temp = dp[0];
        for (int j = 1; j <= n; j++) dp[0] += dp[j];
        for (int j = n; j >= 2; j--) dp[j] = dp[j - 1];
        dp[1] = temp;
    }
    int ans = 0;
    for (int i = 0; i <= n; i++) ans += dp[i];
    cout << ans;
    return 0;
}

逆向 ZJ b515 參考解答

//字串預處理
#include <iostream>
#include <string>
using namespace std;
int main() {
    string temp;
    for (auto &i : "A .- B -... C -.-. D -.. E . F ..-. G --. H ....I .. J .--- K -.- L .-..M -- N -. O --- P .--.Q --.- R .-. S ... T -U ..- V ...- W .-- X -..-Y -.-- Z --..") {
    if (i == ' ') continue;
    if ('A' <= i && i <= 'Z') cout << "\"" << temp << "\", \n", temp = "";
    else temp += i;
    }
    return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main() {
    const string table[26] = {
        ".-",
        "-...",
        "-.-.",
        "-..",
        ".",
        "..-.",
        "--.",
        "....",
        "..",
        ".---",
        "-.-",
        ".-..",
        "--",
        "-.",
        "---",
        ".--.",
        "--.-",
        ".-.",
        "...",
        "-",
        "..-",
        "...-",
        ".--",
        "-..-",
        "-.--"};
    string input;
    cin >> input;
    string ans;
    for (unsigned int i = 0; i < input.size(); i++) {
        ans += table[input[i] - 'A'];
    }
    cout << ans;
    return 0;
}

函式(function)

還有基礎遞迴(recursion)

函式
  • 鍵盤上的Fn鍵
  • 將一堆動作包在一起
  • 類似數學的函數,可以有傳入值、回傳值
  • 動作類似但不像迴圈那麼規律時可用
函式

參數(可無)

回傳值(可無)

函式:處理過程

定義函式
  • 如同變數,使用前要先「宣告」
  • 宣告完後定義這個函式要做什麼
  • 定義:「規範動作」、「規範處理過程」
  • 一般來說宣告完直接定義就行
  • 寫在主函式外面,函式裡面不能宣告/定義其他函式
// 宣告+定義
回傳型別 函式名稱(參數型別1 參數1, 參數型別2 參數2...){
    定義內容
}
// 只有宣告
回傳型別 函式名稱(參數型別1 參數1, 參數型別2 參數2...);
呼叫函式
  • 直接用 函式名稱(參數1, 參數2...) 呼叫就行
  • 拿 std 內建的 min 函式舉例
  • int a = min(5, 4);
參數
  • 不一定要有參數
  • 參數是小括號內的內容,以逗號隔開
  • 參數會從傳入的地方複製一份資料,如果不用參考的話
  • 如果要修改原本地方的資料就記得加參考
  • 如果傳入資料量很大也記得加參考(也可以用常量參考)
回傳值
  • 函式在計算完某東西後經常會回傳某值(像是 sin(x) 會回傳 x 的正弦值)
  • 同一個函式裡的回傳值必須是同一型別
  • 使用 return 回傳, return 同時函式也會終止
  • 不回傳的話型別設成 void ,一樣可以用 return 終止函式

練習:寫一個函式交換 main() 函式裡兩個整數變數的值

參考解答

#include<iostream>
using std::cout;
void swap(int &a, int &b){
    int temp=a;
    a=b;
    b=temp;
    return;
}
int main() {
    int a = 5, b = 3;
    swap(a, b);
    cout << a << ' ' << b; // 3 5
    return 0;
}
遞迴(recursion)
  • 函式的定義用到自己
  • 費波那契數列
  • 遞迴三步驟:
  • 設定「初始狀態」
  • 找出「如何轉移」
  • 思考「何時終止」
f(n) = f(n-1) + f(n-2)\ when\ n>2
遞迴(recursion)

費波那契數列(遞迴Ver.)

int fibonacci(int n) {
    if (n == 1 || n == 2) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

初始狀態:f(1) = f(2) = 1

狀態轉移:f(n) = f(n-1) + f(n-2)

終止時間:n = 1 或 n = 2

練習:利用                                求      ,並分析此函式應該會被呼叫幾次(以 n 表示)

2^n = 2^{n-1} + 2^{n-1}
2^n

再分析如果利用                          會被呼叫多少次

2^n = 2\times2^{n-1}

你能夠想到的最好作法是什麼?(呼叫次數最少?)

改成     呢?

3^n

進階題:求上面求費波那契數列的方法會呼叫多少次函式?(數學)

結構變數/物件

一點點OOP

物件導向(OOP)淺談
  • Object-oriented programming, OOP
  • 將一堆變數包在一起定義一個類別(class)
  • 物件(object):類別的實現
  • 屬性(Attributes):類別包含的變數
  • 方法(method):對屬性的操作
  • 物件當變數用
  • 不管背後怎麼實作
  • FP(Functional Programming)相對
  • 封裝、繼承、多型
結構變數(struct)
#include <iostream>
using namespace std;
struct person {
    double height, weight;
    double BMI() {
        return weight / (height * height);
    }
};
int main() {
    person Sea;
    Sea.height = 1.813;
    Sea.weight = 71.4;
    cout << Sea.BMI();	// 21.7221
}
  • 宣告:struct 結構名{ // ... }; 記得分號
  • 使用 '.' 取得物件的屬性(如果是物件的指標用 "->")
結構變數(struct)
struct person {
    double height, weight;
    double BMI();
};
double person::BMI(){
    return person::weight/(person::height*person::height);
}
  • 使用"::"取得類別屬性
struct person {
    double height, weight;
    struct other{
        double length_of_hair;
        string favorate_food;
    } other_information;
};
  • 可以在struct裡開struct
結構變數(struct)
  • 注意結尾要加分號
  • 在 struct 裡面取屬性不用特別多加什麼
  • 在 struct 裡面不能宣告與自己相同的 struct (循環定義),但可以宣告自己類型的指標
  • 屬性可以有預設值
  • 宣告結構變數時同時做一些事,例如初始化
  • 寫在結構裡時:
  • 結構名(參數型別1 參數1, ...){    // ...    };
  • 之後宣告就用 結構名 結構變數名(參數1...);
struct complex{
    int a, b;
    complex(int _a, int _b){
        a=_a;
        b=_b;
    }
};
int main(){
    complex number(125, 807);
    cout << number.a << ' ' << number.b; // 125 807
    return 0;
}
  • 重新定義運算子,讓結構變數照你想要的樣子用
struct complex {
    int a, b;
    complex(int _a, int _b) {
        a = _a;
        b = _b;
    }
    complex operator+(complex another) {
        return {a + another.a, b + another.b};
    }
};
int main() {
    complex number1(125, 807), number2(123, 456);
    complex sum = number1 + number2;
    cout << sum.a << ' ' << sum.b;
    return 0;
}

ZJ a271 (可以用struct實作一隻兔子)

OJ

(Online Judge)

寫題目的地方

What is OJ
  • 有題目讓你寫的地方
  • 有些有比賽
  • 自動測正確性
一些OJ
  • TIOJ (Temporary INFOR Online Judge)
  • 資訊社的OJ
  • 很多競賽題
  • 題目難
  • 好題多
  • 沒有難度分類
  • 有校內資訊培訓講義
一些OJ
  • Codeforces(CF)
  • 俄國網站
  • 全球最大OJ
  • 英文
  • 積分系統
  • 很多比賽
一些OJ
  • CSES
  • 練習演算法用
  • 時限算鬆,題目很裸,一題可練多種演算法
  • 練基礎300題
  • 照演算法分類
一些OJ
  • AtCoder(AC)
  • 日本網站
  • 很多競賽
  • 積分系統
  • 作息比CF好點
一些OJ
一些OJ
  • ZeroJudge(ZJ)
  • 全臺最多人用OJ
  • 評測系統很糟
  • 爛題不少
  • APCS考古題
  • 照競賽分類
一些OJ
  • ISCOJ
  • 電研的OJ
  • 怪題&哏
  • 還807一個人情
  • 基礎演算法
  • 不要去炸這網站 不然807會宰了我

Contests

其他人分享吧

謝謝大家

暑假資讀[0]

By 海之音

暑假資讀[0]

  • 308