創造力資優課程
computer
C 是丹尼斯·里奇於 1972 年在貝爾實驗室創建的通用程式
儘管它很古老,這是一種非常流行的程式語言。
C 與 UNIX 密切相關,因為它是為編寫 UNIX 作業系統而開發的。
如果您不了解其 #include <stdio.h>工作原理,請不要擔心。只要把它想像成(幾乎)總是出現在你的 c 程式中的東西。
請注意:每句 C 語言程式碼都是以分號 ; 結尾
第 5 行: return 0結束 main( ) 函數。
第 6 行:不要忘記添加右大括號 } 以實際結束 main 函數。
結果: Hello World!I am learning C.
結果:
多行註釋以開頭 /* 和結尾 */。
在 C語言中,不同類型的變數,有規定的宣告方式 例如: int 儲存整數,例如 123 或 -123 ; float 儲存浮點數,帶小數點的數字,例如 19.99 或 -19.99 ; char 儲存單個字元,例如'a' or 'B'。字元值用單引號括起來
輸出 char 變數的值,必須在函數內部使用格式說明符號 %c 用雙引號括起來printf():
輸出 float 變數的值,必須在函數內部使用格式說明符號 %f 用雙引號括起來printf():
名稱可以包含字母、數字和下劃線_ 名稱必須以字母或下劃線 (_) 開頭 名稱區分大小寫(myVar 和 myvar 是不同的變數, 名稱不能包含空格或特殊字符,如 !、#、% 等。 保留字(如int)不能用作名稱//111.9.28
運算子 | 運 算 | Example |
---|---|---|
+ | 加法 | x + y |
- | 減法 | x - y |
* | 乘法 | x * y |
/ | 除法 | x / y |
% | 餘數 | x % y |
++ | 增加1 | ++x |
- - | 減1 | - -x |
運算子 | 例 子 | 等同 |
---|---|---|
= | x =5 | x =5 |
+= | x +=3 | x=x+3 |
-= | x -=3 | x=x-3 |
*= | x *=3 | x=x*3 |
/= | x /=3 | x=x/3 |
%= | x %=3 | x=x%3 |
比較運算子用於比較兩個數值。
注意:比較的結果可能回傳值為 true (1) 或 false ( 0)。
在以下示例中,我們使用大於運算子 > 來確定 5 是否大於 3:
運算子 | 意義 | 例子 |
---|---|---|
== | 等於 | x == y |
!= | 不等於 | x != y |
> | 大於 | x > y |
< | 小於 | x < y |
>= | 大於或等於 | x >= y |
<= | 小於或等於 | x <= y |
邏輯運算子用於確定變量或數值之間的邏輯:
運算子 | 名稱 | 意義 | 舉例 | |
---|---|---|---|
&& | 且 | 兩者都成立 | x < 5 && x < 10 |
|| | 或 | 兩者其中之一成立 | x < 5 || x < 4 |
! | 不是 | 回傳相反值 | !(x < 5 && x < 10) |
1.如何判斷一個給定的數字是偶數還是奇數?
2.輸入一個整數後即輸出該數的絶對值
3.判斷三條線段是否可圍成一個三角形
如何判斷一個給定的數字是偶數還是奇數?
在三個數字中,找出最大的一個數字
1.判斷 3 條線段是否可圍成三角形:
他的占卜規則很簡單,規則是這樣的,輸入一個日期,然後依照下面的公式:
M=月 D=日 S=(M*2+D)%3
得到 S 的值,再依照 S 的值從 0 到 2 分別給與 普通、吉、大吉 等三種不同的運勢
break 可以節省大量執行時間,因為它“忽略”了 switch 區塊中其餘程式的執行。
default 關鍵字必須是 switch 區塊中的最後一段陳述,並且不一定需要 break。
我國的身分證字號有底下這樣的規則,因此對於任意輸入的身分證字號可以有一些基本的判斷原則,請您來判斷一個身分證字號是否是正常的號碼(不代表確有此號、此人)。
(1) 英文代號以下表轉換成數字
A=10 台北市 J=18 新竹縣 S=26 高雄縣
B=11 台中市 K=19 苗栗縣 T=27 屏東縣
C=12 基隆市 L=20 台中縣 U=28 花蓮縣
D=13 台南市 M=21 南投縣 V=29 台東縣
E=14 高雄市 N=22 彰化縣 W=32 金門縣
F=15 台北縣 O=35 新竹市 X=30 澎湖縣
G=16 宜蘭縣 P=23 雲林縣 Y=31 陽明山
H=17 桃園縣 Q=24 嘉義縣 Z=33 連江縣
I=34 嘉義市 R=25 台南縣
(2) 英文轉成的數字, 個位數乘9再加上十位數的數字
(3) 各數字從右到左依次乘1、2、3、4....8
(4) 求出(2),(3) 及最後一碼的和
(5) (4)除10 若整除,則為 real,否則為 fake
例: T112663836
除以 10 整除,因此為 real
請設計一個找零機器的判斷程式,判斷使用者輸入的金額( money)當中,以最少的銅板數來找零錢。該機器所提供的銅板有 50 元、10 元、5 元及 1 元。當輸入的金額數介於 1 到 1000 之間,則依序顯示該找的各個銅板數(50 元、10 元、5 元及 1 元);當金額為 0 時,則結束判斷。
break 還可用於跳出 while 、for 迴圈。
下面例子在 i 等於 4 時跳出迴圈:
以下例子輸出myNumbers 陣列中的所有元素:
你已經學過,用 printf() 輸出數值的方法。
要用戶輸入數值,可以使用 scanf()
例子
指定一段程式碼,執行特定的工作。
可重複呼叫使用
讓程式變得容易閱讀理解。
在呼叫函式條件不改變的狀態下,可以直接修改函式的程式。
函式分為系統定義函式(如printf)和使用者定義函式兩種。
系統定義函式(標準函式庫): 需呼叫標頭檔例如:
標準函式庫是C語言標準提供的函式庫,包含了大量的函式,可以幫助開發者簡化程式設計,加速開發速度。標準函式庫通常可以被編譯器直接調用,而不需要開發者自己編寫相關的代碼。
C語言的標準函式庫可以分為幾個部分,每個部分包含了不同類型的函式:
標準輸出/輸入函式庫:包括了與螢幕和鍵盤輸入輸出有關的函式,例如printf、scanf等。
字符串函式庫:包括了與字串處理有關的函式,例如strlen、strcpy、strcat等。
數學函式庫:包括了與數學運算有關的函式,例如sqrt、sin、cos等。
時間函式庫:包括了與時間有關的函式,例如time、ctime、gmtime等。
檔案操作函式庫:包括了與檔案操作有關的函式,例如fopen、fclose、fread等。
其他函式庫:還包括了與動態記憶體分配、環境變數、數據類型轉換等相關的函式。
在下方的程式中,當我們程式跑到 f(4)中,代表他呼叫了上方 int f(int x) 函式,而因為這個函式有回傳值,所以在進行計算過後,我們有一個return x+3,把計算過後的答案傳回到主程式中 f(4) 就會等於回傳值 7,印出答案後程式結束執行。
int f(int x){ return x +3; }
練習題:利用函式寫一個判斷閏年的程式
在函式原型宣告時,第一個宣告的元素就是函式的傳回值的資料型別,任何的基本資料型別(如int, char, float, double…等)或自訂的資料型別都可以使用,但是如果函式不傳回任何值,則我們要把資料型別宣告為void,意思是不傳回值。
練習寫一個無回傳值的計算面積公式
而要如何知道第 n-1 項是多少呢?我們這時就需要知道第 n-2與第 n-3 項,如此類推,最後直到我們想要知道的項為第 0 項與第 1 項時,因為這兩項已經被定義了,所以我們就能一一解答前面的所有項了。
還是有點抽象嗎?讓我們以計算 n=5 時的費波那契數列為例,他在進行函式執行時的呼叫順序如下:
而要找到數列的第 5 個數,我們需要的層數是剛好是 5 層,而推展到第 n 個數時,我們剛好需要 n 層。這個部分如果有點抽象的話,可以直接觀察上面的例子,圖中每一層的最左邊那項,是從 F(n) 一路遞減到 F(1),這樣剛剛好會是 n 層。
綜合結論:時間複雜度約等於為 O(2ⁿ) (2 的 n 次方)。
練習題:
寫一個程式,它可以處理任何筆數的成績,來處理全班分數。
第二個工作:重複輸入,直到輸入「-1」,才停止。 請輸出「輸入的分數筆數」。
輸入範例: 75 75 75 88 70 64 83 89 -1
輸出範例: 8
冒牌費氏數列 令:
請寫一個程式,輸入n,輸出f(n)值。
輸入範例: 5
輸出範例: 31
[如何將C語言程式轉換成執行檔.exe格式]
給定三根柱子與數個不同大小的盤子,要求依照一定規則(每次只移動一個盤子,且大盤子不能放到小盤子上)將所有盤子從起點柱子搬運到目標柱子上。
📌 二、問題特性與時間複雜度: 明確的遞迴解法:
河內塔問題有非常清晰的遞迴(Recursive)解法,可以在每一步遞迴中明確決定下一步該怎麼做。
演算法時間複雜度:
解決 N 個盤子的河內塔,所需步驟為 2ⁿ-1。
雖然看起來是指數成長,但仍屬於確定性演算法,且能夠清晰、直接地計算出每一步。
驗證解法:
不僅可以在多項式時間內驗證答案的正確性,還可以明確快速(多項式時間)地直接得到每一步的搬運順序。
📌 三、為何是 P 問題而非 NP 問題:
項目 河內塔問題特性 是否能有效求解? ✅ 可以快速且明確地找到解法 驗證答案正確性? ✅ 容易驗證(每一步都可以快速確認) 時間複雜度性質 ✅ 指數級但有明確且固定的步驟,屬於可有效計算 由於可有效地用一個確定性演算法解決,因此河內塔問題屬於 P 問題。
NP 問題的特性是可以快速驗證,但不一定能快速解決,典型如旅行推銷員問題(TSP)。
P 問題則是可快速找到有效的解法,典型如河內塔。
📌 四、為什麼河內塔是 P 但複雜度又是指數? 這裡需要釐清一點:
河內塔的最佳步驟數量是指數成長 𝑂(2ⁿ),但這個步驟數量是「已知且確定的」,能用一個非常簡單且明確的演算法(遞迴)精準求出答案,因此依計算複雜度理論的定義,它仍然被歸類在 P 問題的範疇內。
P 問題強調能用確定性的多項式時間演算法去求出解答步驟,而河內塔問題恰巧符合這種明確演算法的條件。
簡言之,河內塔問題雖步驟數指數級,但求解演算法簡明、確定,不具 NP 問題的「不確定性」特性。
在「複雜度理論」的角度,我們可以這樣判斷:
P 問題(Polynomial time):可以在多項式時間內解出正確答案的問題。
NP 問題(Nondeterministic Polynomial time):如果給你一個「猜測答案」,你能在多項式時間內驗證這個答案對不對,但找到這個答案不一定容易。
幾A幾B猜數字遊戲是屬於哪一種?
答案是:
驗證一個猜測是否正確很快(只要比對兩組數字,看幾A幾B,用 O(n) 時間可以完成),所以這個問題一定屬於 NP。
至於「找到正確答案」這件事,有沒有辦法保證用多項式步驟內完成?
如果答案空間很大(例如猜的是 10 位數、數字可以重複),暴力猜測需要指數級的時間。
但如果題目的設定是小範圍(像猜 3 位數、不重複數字),人或電腦可以在合理步數內解出來。
所以一般來說,完整的「幾A幾B遊戲」屬於 NP 問題,但不一定是 NP-Complete。
如果限制輸入規模(例如最多 4 位數),那這種猜數字遊戲在實務上可以視為 P 問題; 但如果放寬規模(數字任意長),它就屬於 NP,甚至可能趨向 NP-hard。
簡單一句話總結: ➔ 「幾A幾B猜數字遊戲是 NP 問題,不一定是 P 問題。」 (可以快速驗證,但不保證可以快速找到答案,尤其當範圍變大時。)
玩家每猜一次數字後,遊戲系統會告知「過大」或「過小」的提示。
玩家根據提示逐步縮小範圍,直到找到正確答案。
📌 二、為什麼是P問題: 有效演算法求解:
有明確且有效的演算法(如二分搜尋法),每次都能將可能的數字範圍縮小一半。
假設數字範圍為 1 到 n,最多只需 log₂n 次即可確定答案,屬於多項式時間內解決(甚至是對數級別,更快於一般多項式級)。
快速驗證:
不論是猜測還是驗證,都可以迅速完成。
📌 三、與NP問題的比較:
特性 終極密碼猜數字(P問題) NP問題(如旅行推銷員) 能否快速解決? ✅ 是 ❌ 不確定,目前未知快速解法 驗證答案是否快速? ✅ 是 ✅ 是 最佳解法 ✅ 有效解法:二分搜尋法 ❌ 一般只能暴力窮舉求解 終極密碼遊戲與NP問題(如背包問題或旅行推銷員問題)本質上不同。NP問題通常沒有已知的有效求解演算法;但終極密碼遊戲則有明確、高效率的求解方法(二分法)。
📌 四、終極密碼遊戲的時間複雜度: 使用最佳策略(二分搜尋)解題: 時間複雜度=O(log₂n ) 屬於非常有效率、快速解決的問題。
🌟 結論: 終極密碼猜數字遊戲屬於P問題,而非NP問題。 因為它具備快速、有效、確定性的求解方法(二分搜尋法),且其複雜度非常低。
TSP被歸為NP問題的主要原因,是因為我們尚未找到一個高效率的、多項式時間(polynomial-time)內求解的演算法。要找到TSP的最佳解,目前最直接的方法便是窮舉所有可能的路徑,計算每條路徑的長度,最後選出最短的路線。然而,對於n個城市,窮舉所有可能的路徑數量為(n-1)!,隨著城市數量增加,運算量呈現指數級成長,這種增長速度非常迅速,以致於在實務中難以有效求解。
儘管求解困難,但若給定一個可能的解答,要驗證這條路徑是否為有效路徑、以及是否滿足特定的總距離限制,卻是相對容易的,可以快速地在多項式時間內完成驗證。因此,TSP符合NP問題的重要特徵,也就是能夠快速驗證答案,但並不確定能否快速求解答案。
另外,TSP問題經典而重要的原因,在於它是「NP完全問題」(NP-complete) 中最具代表性的一種,NP完全問題是指一類問題,只要其中一個問題被證明能夠有效解決,則所有的NP問題都能有效解決。換言之,若有人能找到TSP的快速解法,則所有其他的NP問題也能一併被解決,這也正是電腦科學界至今對此問題投入大量研究心力的主要原因之一。
背包問題被認定為NP問題,主要是因為目前尚未找到一個能在多項式時間內有效解決所有情況的演算法。對於n個物品,每一個物品都有「放入」或「不放入」兩種選擇,因此總共有 2ⁿ 種可能的組合。要找到最佳解,最直接的方法是窮舉所有可能的物品組合,計算其總重量與總價值,再從中選出符合條件且價值最大的組合。由於組合數量隨著物品數量指數級成長,當n很大時,窮舉法變得極度耗時,因此無法在多項式時間內保證找到最佳解。
然而,若有人提供了一個特定的物品選擇方案,我們可以很容易地在多項式時間內驗證它是否合法(是否沒有超過承重且達到特定價值)。這正符合NP問題的定義:雖然不一定能快速找到解,但若有一個解,可以在多項式時間內驗證其正確性。
此外,背包問題有許多變體,如0/1背包問題、分數背包問題等。其中,「0/1背包問題」(每個物品只能選或不選)是典型的NP完全問題(NP-complete),也就是說,它不僅是NP問題,而且是最難的NP問題之一。這代表如果能找到一個多項式時間內解決0/1背包問題的方法,就能解決所有NP問題。
總結來說,背包問題因為符合「難以快速求解,但能快速驗證答案」的特徵,因此被歸類為NP問題,並且在理論計算與實務應用中都具有重要意義。