2017北一女中 資訊能力競賽 暑期培訓營 Anny@T.F.G.

Slides:



Advertisements
Similar presentations
CSIM, PU C Language Introduction to the C Programming Language 重覆敘述 (for,while,break,continue) 適合重複性的計算或判斷.
Advertisements

C语言程序设计 主讲教师 :张群燕 电话:
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
Loops.
第一章 C语言概述 计算机公共教学部.
補充: Input from a text file
专题研讨课二: 数组在解决复杂问题中的作用
C语言程序设计 第八章 函数.
C语言程序设计 第十二章 位运算.
第一章 程序设计入门.
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
C语言程序设计 第五章 选择结构程序设计.
第六章 数 组 主讲教师 贾月乐 联系电话:
高级语言程序设计 主讲人:陈玉华.
循环结构又称为重复结构:用来处理需要重复处理的问题,它是程序中一种很重要的结构。
第3章 顺序结构程序设计 本章要点: 格式化输出函数──printf() 格式输入函数——scanf() 字符输出函数——putchar()
东北林业大学 陈宇 ACM程序设计 东北林业大学 陈宇
C++程序设计 第二讲 清华大学软件学院.
第四章 函数和递归.
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数 10.3 宏定义 10.4 编译预处理.
C程序设计.
第五章 选择结构程序设计 一、关系运算符和表达式 1、关系运算符 在程序中经常需要比较两个量的大小关系, 以决定程序下一步
C 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
Chap 2 用C语言编写程序 2.1 在屏幕上显示 Hello World! 2.2 求华氏温度 100°F 对应的摄氏温度
C++ 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
STRUCTURE 授課:ANT 日期:2010/5/12.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Function.
C 語言簡介 - 2.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
2017北一女中 資訊能力競賽 暑期培訓營
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
QQ: 李祥 QQ: 欢迎多种方式的学习交流,祝大家学有所成.
第二章 基本元素、类型和概念 七、输出函数printf 八、输入格式转换函数scanf.
Introduction to the C Programming Language
作弊是否很有诱惑性? 上堂课已经讲了 作业不一定在两个小时里都能完成 答疑没有一个人? 作弊是有记录的 心理系很多同学集体作弊,让人震惊
第四章 C 语言中的输入和输出.
C语言 程序设计基础与试验 刘新国、2012年秋.
THE C PROGRAMMING LANGUAGE
本章中將會更詳細地考慮有關重複的概念,並且會 介紹for和do…while等兩種用來控制重複的敘述 式。 也將會介紹switch多重選擇敘述式。 我們會討論直接和迅速離開某種控制敘述式的 break敘述式,以及用來跳過重複敘述式本體剩餘 部份的continue敘述式。 本章會討論用來組合控制條件的邏輯運算子,最後.
2017北一女中 資訊能力競賽 暑期培訓營
第三章 顺序结构程序设计 主讲教师 贾月乐 电话:
2.1 C语言的数据类型 2.2 常量与变量 2.3 变量赋初值 2.4 各类数值型数据间的混合运算 2.5 C语言的运算符和表达式
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第4章 顺序程序设计.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C语言概述 第一章.
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
第3章 變數、算術運算、 數學函數及輸入輸出.
第 二 章 数据类型、运算符与表达式.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
程式的時間與空間 Time and Space in Programming
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
C程序设计.
C语言程序设计 李祥 QQ:
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第2章 基本数据及其运算 本章学习的目标: 1、掌握基本数据的各种表示,基本数据常数的书写方法;
第3章 最简单的C程序设计 3.1 顺序程序设计举例 3.2 数据的表现形式及其运算 3.3 C语句 3.4 数据的输入输出.
結構、檔案處理(Structure, File)
Chap 7 数 组 7.1 排序问题 7.2 找出矩阵中最大值所在的位置 7.3 进制转换.
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
Chap 10 函数与程序结构 10.1 圆形体积计算器 10.2 汉诺塔问题 10.3 长度单位转换 10.4 大程序构成.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
函式庫補充資料 1.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

2017北一女中 資訊能力競賽 暑期培訓營 Anny@T.F.G

練習進度調查 https://goo.gl/forms/fDQRTAnYgOKTXDUo2

【培訓用書】 程式設計與演算法競賽入門經典(劉汝佳/著,H&C/譯) Part I 語言篇 chapter 01 程式設計入門 chapter 02 迴圈結構程式設計 chapter 03 陣列和字串 chapter 04 函數和遞迴 chapter 05 C++ 與 STL 入門 Part II 基礎篇 chapter 06 資料結構基礎 chapter 07 暴力求解法 Part III 競賽篇 chapter 08 高效演算法設計 chapter 09 動態規劃初步 chapter 10 數學概念與方法 chapter 11 圖論模型與演算法 chapter 12 進階專題 Appendix A 開發環境與方法 主要參考書目 【培訓用書】 程式設計與演算法競賽入門經典(劉汝佳/著,H&C/譯) http://www.books.com.tw/products/0010650143

【APCS】 大學程式設計先修檢測 程式設計觀念題 程式設計實作題 單選題,以運算思維、問題解決與程式設計觀念測試為主。 測試包含 code tracing, code completion, code debugging 等題型。 題目若需提供程式片段,則以 C subset 語言命題(參考文件下載  )。 作答結果由系統自動儲存,無須上傳。 >>>查看觀念題_範例試題   程式設計實作題 實作題,撰寫完整程式或副程式。 測驗者可自選程式語言( C, C++, Java, Python )撰寫程式。 須透過系統上傳原始程式碼。若上傳多次,評分時以最後上傳版本為準。 >>>查看實作題_範例試題 https://apcs.csie.ntnu.edu.tw/index.php/samplequestions

【APCS】 命題範圍 (2016.12.22更新) Programming Concepts Data types, constant, variable, Global, Local Control structures Loop structures Functions Recursion Array and Structures

【APCS】 大學程式設計先修檢測 《觀念題》 https://apcs.csie.ntnu.edu.tw/index.php/samplequestions/conceptquestions 《實作題》 https://apcs.csie.ntnu.edu.tw/index.php/samplequestions/implementationquestions

【培訓課程】 Day1: 程式競賽基礎 Day2: 陣列與字串 Day3: 函數與遞迴 Day4: 搜尋、排序、堆疊、佇列

Day1: 程式競賽基礎 C語言輸入輸出 掌握整數與浮點數含義(數值範圍)與輸出方法 理解程式競賽三步曲:輸入、計算、輸出 掌握迴圈(for, while), 計數器、累加器使用 學會程式逐步除錯方法(變數watch功能) 學會用fopen的方式讀寫檔案

C語言輸入輸出格式 #include <stdio.h> int main() { int a, b; scanf("%d%d", &a, &b); printf("%d\n", a+b); return 0; } Hint: stdio.h scanf printf &a &b int %d \n return 0

例題1-1 圓柱體的表面積 輸入底面半徑r和高h, 輸出圓柱體的表面積。 保留3位小數,格式請見範例。 範例輸入: 3.5 9 範例輸出: Area = 274.889

解析:表面積=上底面積+下底面積+側面積 Hint: math.h const Pi = acos(-1.0); double %lf float %f int %d return 0 #include <stdio.h> #include <math.h> int main() { const double pi = acos(-1.0); double r, h, s1, s2, s; scanf("%lf%lf", &r, &h); s1 = pi * r * r; s2 = 2 * pi * r * h; s = s1 * 2.0 + s2; printf("Area = %.3lf\n", s); return 0; }

例題1-2 三位數反轉 輸入一個三位數,分離出它的百位、十位和個位,反轉後輸出。 範例輸入 127 範例輸出 721

例題1-2 三位數反轉(1) #include <stdio.h> int main() { int n; scanf("%d", &n); printf("%d%d%d\n", n%10, n/10%10, n/100); return 0; }

例題1-2 三位數反轉 測資: 520 輸出結果: 025 還是 25

例題1-2 三位數反轉(2) #include <stdio.h> int main() { int n, m; scanf("%d", &n); m = (n%10)*100 + (n/10%10)*10 + (n/100); printf("%03d\n", m); return 0; }

例題1-2 三位數反轉 測資: 520 123 200 輸出結果: 025 321 002

例題1-3 交換變數 輸入兩個整數a和b, 交換二者的值,然後輸出。 範例輸入 824 16 範例輸出 16 824

例題1-3 交換變數 (三變數法) #include <stdio.h> int main() { int a, b, t; scanf("%d%d", &a, &b); t = a; a = b; b = t; printf("%d %d\n", a, b); return 0; }

例題1-4 雞兔同籠 已知雞和兔的總數量為n, 總腳數為m。輸入n和m,依次輸出雞的數目和兔的數目。如果無解,則輸出「No answer」(不要引號)。 範例輸入1 14 32 範例輸出1 12 2 範例輸入2 10 16 範例輸出2 No answer

例題1-4 雞兔同籠 分析:(已知雞和兔的總數量為n, 總腳數為m) 設雞有 a 隻,兔有 b隻,則 a+b = n 2a+4b=m 解聯立,得 a = (4n-m)/2 b= n-a; 思考:何時為無解呢? 正確的是:a, b 皆為整數且 a,b皆必須為非負數。

例題1-4 雞兔同籠 Hint: a, b 皆為整數且 a,b皆必須為非負數 Why m%2==1 #include <stdio.h> int main() { int a, b, n, m; scanf("%d%d",&n,&m); a = (4*n-m) / 2; b = n - a; if (m % 2 == 1 || a <0 || b<0) printf("No answer\n"); else printf("%d %d\n", a, b); return 0; }

例題1-5 三整數排序 輸入3個整數,從小到大排序後輸出 範例輸入: 20 7 33 範例輸出: 7 20 33 Hint: a, b,c a c b b a c b c a c a b c b a

例題1-5 三整數abc排序 #include <stdio.h> int main() { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (a<=b && b<=c) printf("%d %d %d\n", a, b, c); else if (a<=c && c<=b) printf("%d %d %d\n", a, c, b); else if (b<=a && a<=c) printf("%d %d %d\n", b, a, c); else if (b<=c && c<=a) printf("%d %d %d\n", b, c, a); else if (c<=a && a<=b) printf("%d %d %d\n", c, a, b); else if (c<=b && b<=a) printf("%d %d %d\n", c, b, a); return 0; }

例題1-5 三整數abc排序 #include <stdio.h> int main() { int a, b, c, t; scanf("%d%d%d", &a, &b, &c); if (a>b) { t = a; a = b; b = t;} //執行完畢後 a<=b if (a>c) { t = a; a = c; c = t;} //執行完畢後 a<=c 且 a<=b if (b>c) { t = b; b = c; c = t;} printf("%d %d %d\n", a, b, c); return 0; }

總結 比賽時 無論使用C語言程式還是C++程式,都要把程式存成 .cpp,並且與C++ 程式提交。 留意格式問題 重視實驗 學會模仿 int %d float %f double %lf long long %lld (%I64d MinGw gcc) %.3lf, %.0lf, %.2f %3d %03d printf("…..\n") return 0; 重視實驗 學會模仿

簡單習題 3 數平均數(average.cpp) 攝氏(c)華氏(f)溫度轉換(temperature.cpp) 連續數字a…b之和(sum.cpp) n(n<360)度的正弦與餘弦(sincos.cpp) 打折(discount.cpp) 三角形判定(triangle.cpp) 閏年判定(year.cpp)

迴圈結構程式設計 For, while… 迴圈的使用方法 計數器、累加器 輸出中間結果除錯 使用計時函數測式效率 學會 freopen()重新導向方式讀寫檔案 學會 fopen()的方式讀寫檔案

for 迴圈 #include <stdio.h> int main() { int a=1,b=10; int sum=0; for (int i = a; i<= b; i++) sum += i; printf("%d\n", sum); return 0; } Hint: 觀察 i ,sum 的變化

Code Block Debugger(1) 開新專案(File/new/project…/console application/Go, Next, C++, project title, 例:myproject)

Code Block Debugger(2) 寫程式(在main.cpp裡寫程式)

Code Block Debugger(3) 按右鍵增加紅色中斷點Add breakpoints

Code Block Debugger(4) 開始除錯 (F8) 停止除錯 (Shift –F8)

Code Block Debugger(5) 觀看變數 Add watches Run to cursor / next line

例題2-1 aabb 完全平方數 輸出所有像是aabb的四位完全平方數 即, 前兩位數字相等,後兩位數字也相等 思考:1100,1111,1122,1133,1144,…,9999 那些是完全平方數

例題2-1 aabb 完全平方數 分析:n = aabb n = a * 1100 + b * 11 (a:1~9, b:0~9) m = sqrt(n) 四捨五入後的整數 再判斷 m2 是否等於 n

例題2-1 aabb 完全平方數 #include <stdio.h> #include <math.h> int main() { for (int a = 1; a<=9; a++) for (int b=0; b<=9; b++) int n = a * 1100 + b*11; int m = floor(sqrt(n)+0.5) ; if (m*m == n) printf("%d\n",n); } return 0; Hint: n = a * 1100 + b * 11 (a:1~9, b:0~9) m = sqrt(n) 四捨五入後的整數 再判斷 m2 是否等於 n Hint: sqrt()函數 floor()函數

例題2-2 3n+1問題 對於任意大於1的自然數n,若n為奇數,則將n變為3n+1, 否則變為n的一半。 經過若干次這樣的變換,一定會使n變為1。 例如:3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1。 輸入n, 輸出變換的次數。 N <= 109。 範例輸入 3 範例輸出 7

例題2-2 3n+1問題 解題分析: 迴圈的次數不確定, n也不是遞增、遞減式的迴圈 適合使用 while迴圈 if (n 是奇數) n = 3*n + 1 else n=n/2 一直做,直到 n 為 1

例題2-2 3n+1問題 #include <stdio.h> int main() { int n, count = 0; scanf("%d", &n); while(n > 1) if (n%2==1) n = 3*n + 1; else n = n/2; count ++; } printf("%d\n", count); return 0; Hint: 初始化問題 迴圈重複條件 == 運算子 注意輸出結果要換行 \n

例題2-2 3n+1問題 測試一下: 3 11111 555555 987654321 -- 7 55 146 1 Hint: 不要忘記測試 一個看起來正確的程式可能隱含錯誤 若觀察無法找出錯誤,可以「輸出中間結果」

例題2-2 3n+1問題 Hint: 不要忘記測試 一個看起來正確的程式可能隱含錯誤 若觀察無法找出錯誤,可以「輸出中間結果」 留意 溢位 問題 思考: int 32 位元整數 %d 數值範圍 -231 ~ 231-1 -2147483648 ~ 2147483647 long long 64位元整數 %lld (或 %I64d) -263 ~ 263-1

例題2-2 3n+1問題 Hint: long long n; 解決溢位問題 n <= 109 n = 3*n + 1 #include <stdio.h> int main() { int n2, count = 0; scanf("%d", &n2); long long n = n2; while(n > 1) if (n%2==1) n = 3*n + 1; else n = n/2; count ++; } printf("%d\n", count); return 0; Hint: long long n; 解決溢位問題 n <= 109 n = 3*n + 1

例題2-2 3n+1問題 測試一下: 3 11111 555555 987654321 -- 7 55 146 1  180 Hint: 不要忘記測試 一個看起來正確的程式可能隱含錯誤 若觀察無法找出錯誤,可以「輸出中間結果」

例題2-3 近似計算 計算 pi/4 = 1 – 1/3 + 1/5 – 1/7 +… 直到最後一項小於10-6

例題2-3 近似計算 計算 pi/4 = 1 – 1/3 + 1/5 – 1/7 +… 直到最後一項小於10-6 分析: i =0 ~ (未知), i++ 第i項( term )= 1.0 / (i*2+1) 處理一正一負的問題 一直做,直到 term <10-6

#include <stdio.h> int main() { double sum = 0; for (int i=0; ; i++) double term = 1.0 / (i*2 +1); if (i%2==0) sum += term; else sum -= term; if (term < 1e-6) break; } printf("%.6lf\n",sum); return 0; 例題2-3 近似計算 Hint: for (int i=0; ; i++) { if (….) break; } 1e-6: 1* 10-6

程式競賽中的輸入輸出框架 Hint:重複輸入 輸入完畢先按Enter, 再按Ctrl-Z, 最後再按Enter, 即可結束輸入 while (scanf("%d", &n) == 1) { // } while (scanf("%d%d", &n, &m) == 2) Hint:重複輸入 輸入完畢先按Enter, 再按Ctrl-Z, 最後再按Enter, 即可結束輸入

例題2-5 資料統計 輸入一些整數,求它們的最小值、最大值和平均值(保留3位小數)。 輸入保證這些數都不超過1000。 範例輸入:2 8 3 5 1 7 3 6 範例輸出:1 8 4.375

例題2-5 資料統計 (bug) Hint: 初值設定的重要性 #include <stdio.h> int main() { int x, n=0, min, max, s= 0; while (scanf("%d", &x)==1) s += x; if (x < min) min = x; if (x > max) max = x; n++; } printf("%d %d %.3f", ,min, max, (double)s /n); return 0; Hint: 初值設定的重要性

例題2-5 資料統計 (重新導向) Hint: freopen() #ifdef #define #define LOCAL #include <stdio.h> #define INF 1000000000 int main() { #ifdef LOCAL freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif // LOCAL int x, n=0, minx = INF, maxx= -INF, s= 0; while (scanf("%d", &x)==1) s += x; if (x < minx) minx = x; if (x > maxx) maxx = x; //printf("%d %d %.3f", ,minx, maxx, (double)s /n); n++; } printf("%d %d %.3f",minx, maxx, (double)s /n); return 0; 例題2-5 資料統計 (重新導向) Hint: freopen() #ifdef #define

#include <stdio. h> #define INF 1000000000 int main() { FILE #include <stdio.h> #define INF 1000000000 int main() { FILE *fin, *fout; fin = fopen("data.in", "rb"); fout = fopen("data.out", "wb"); int x, n=0, minx = INF, maxx= -INF, s= 0; while (fscanf(fin, "%d", &x)==1) s += x; if (x < minx) minx = x; if (x > maxx) maxx = x; //printf("%d %d %.3f", ,minx, maxx, (double)s /n); n++; } fprintf(fout, "%d %d %.3f",minx, maxx, (double)s /n); fclose(fin); fclose(fout); return 0; 例題2-5 資料統計 (fopen) Hint: FILE *fin, *fout; fin = fopen("data.in", "rb"); fout = fopen("data.out", "wb"); fclose(fin); fclose(fout); fscanf() fprintf()

習題 p2-22~p2-24 水仙花數(daffodil) 韓信點兵(hanxin) 倒三角形(triangle) 子序列之和(subsequence) 分數化小數(decimal) 排列(permutation)

水仙花數(daffodil) 輸出100~999中的所有水仙花數。 水仙花數為3位數ABC並滿足 ABC = A3 + B3 + C3, 例如153 = 13 + 53 +33,則153為水仙花數。

韓信點兵(hanxin) 相傳韓信才智過人,從不直接清點自己軍隊的人數,只要讓士兵先後以三人一排、五人一排、七人一排地變換隊形,而他每次只看一下隊伍的排尾就知道總人數了。 輸入3個非負整數a,b,c,表示每種隊形排尾的人數(a<3,b<5,c<7),輸出總人數的最小值(或報告無解)。 已知總人數不小於10,不超過100。 範例輸入:2 1 6 範例輸出:41 範例輸入:2 1 3 範例輸出:No answer

倒三角形(triangle) 輸入正整數n<=20,輸出一個n層的倒三角形。例如,n=5時輸出如下: ######### ####### ##### ### #

#include <stdio.h> int main() { int n; scanf("%d", &n); for (int i = n; i >= 1; i--) for(int j = n; j > i; j--) //每一層前輸出的空格數,第一層沒有空格 printf(" "); for(int k = 2*i-1; k>0; k--) printf("#"); printf("\n"); } return 0; 倒三角形(triangle)

子序列之和(subsequence) 輸入兩個正整數<m<106,輸出1/n2 + 1/(n+1)2 + …… + 1/m2,保留5位小數。輸入包含多組資料,結束標記為n=m=0。提示:本題有陷阱。 範例輸入: 2 4 65536 655360 0 0 樣例輸出: Case 1:0.42361 Case 2:0.00001

#include <stdio.h> int main() { int n, m, i; while( scanf("%d%d", &n, &m) != EOF) double sum = 0; for(i = n; i <= m; i++) sum += 1.0/i/i; printf("%.5f\n", sum); } return 0; 子序列之和(subsequence)

子序列之和(subsequence) 本題陷阱在於n比較大時,n*n會溢出 所以 1/n^2 應該用 1/n/n 而不是 1/(n*n) 如果沒有sum = 0;,後面的輸出是前一次輸出和本次輸出之和。

分數化小數(decimal) 輸入正整數a, b, c,輸出a/b的小數形式,精確到小數點後c位。a, b <= 10^6,c <= 100。輸入包含多組資料,結束標記為a=b=c=0. 範例輸入: 1 6 4 0 0 0 範例輸出: Case 1:0.1667

//version 1 未考慮double型資料的有效數字只有15-16位 #include <stdio //version 1 未考慮double型資料的有效數字只有15-16位 #include <stdio.h> int main() { int a,b,c,count=1; while(scanf("%d%d%d",&a,&b,&c)!=EOF){ if(a==0&&b==0&&c==0) break; printf("Case %d:%.*lf\n",count++,c,(double)(a)/b); //printf("%*.*lf", x, y, z); //意思是輸出頻寬為x,小數點後y為的double型數據z } return 0; 分數化小數(decimal) 可用 1 6 58 測試。

分數化小數(decimal) 可用【3930 1687 4】、【3930 1687 3】測試。 //version 2 未考慮小數部分第c位是9,即四捨五入後還需進位 #include <stdio.h> int main() { int a,b,c,tmp,count=1; while (scanf("%d%d%d", &a, &b, &c) != EOF){ if (a==0 && b==0 && c==0) break; printf("Case %d:%d.", count++, a / b); //整數部分 a = a % b * 10 ; while(c-->1){ //小數點後前c-1位 printf("%d", a/b); a = a % b * 10; } tmp = a % b * 10 /b; //tmp是初始a/b的小數點後第c+1位元數字 if (tmp < 5) printf("%d\n", a / b ); else printf("%d\n", a / b + 1); return 0; 分數化小數(decimal) 可用【3930 1687 4】、【3930 1687 3】測試。

//version 3 #include <stdio //version 3 #include <stdio.h> int main() { int a,b,c,tmp,i,t,count=1; int s[110];//用於保存小數點後的部分 while(scanf("%d%d%d",&a,&b,&c)!=EOF){ if(a==0&&b==0&&c==0) break; t=a/b; a=a%b*10; for(i=1;i<c;i++){//小數點後前c-1位元保存到陣列s中 s[i]=a/b; } tmp=a%b*10/b;//tmp是初始a/b的小數點後第c+1位元數字 if(tmp<5) s[i]=a/b;//s[i]即s[c] else s[i]=a/b+1; while(i>1){ if(s[i]==10){ s[i]-=10; s[i-1]+=1; i--; if(s[1]==10){ s[1]-=10; t++; printf("Case %d:%d.",count++,t); for(i=1;i<=c;i++) printf("%d",s[i]); printf("\n"); return 0; 分數化小數(decimal)

排列(permutation)

Day2: 陣列與字串 掌握一維陣列、二維陣列的宣告與使用 memset, memcpy (string.h) 掌握字串宣告、指定值、比較與連接方式 熟悉ASCII碼與ctype.h的字元函數 競賽題目精選:UVa272, 10082, 401, 340, 1583, 1584 1585, 1586, 1225, 455, 227, 232, 1368, 202, 10340, 1587

3-1 逆序輸出 讀入不超過100個整數。 任務:逆序輸出,以空白隔開。 範例輸入:1 2 3 4 5 7 8 9 範例輸出:9 8 7 5 4 3 2 1 最後記得換行

3-1 逆序輸出 解析: 開一整數陣列 (思考大小 : 100? 10000?) 連續輸入放入陣列中 輸出格式

3-1 逆序輸出 #include <stdio.h> #define maxn 105 int a[maxn]; int main() { int x, n=0; while (scanf("%d", &x)==1) a[n++]=x; //連續讀入 for (int i = n-1; i>0; i--) printf("%d ", a[i]); //印出前n-1個 printf("%d\n", a[0]); //處理最後一個 return 0; } x 1 7 39 52 15 26 37 CtrlZ 2 3 4 5 6 a[0] a[1] a[2] a[3] a[4] a[5] a[6] n Hint: n++, maxn, 陣列宣告的位置 a[n++]=x; 代表 a[n]=x; N++; 輸出 a[6]~a[1]空格隔開 輸出 a[0] 換行

3-2 開燈問題 有 n 盞燈,編號為1~n。 第1個人把所有燈打開,第2個人下所有編號為2的倍數的開關(這些燈將被關掉) 第3個人按下所有編號為3的倍數的開關(關掉的燈將被打開,開著的燈將被關掉) 依此類推。 一共有 k 個人,問最後有哪些燈開著? 輸入:n和k,輸出:開著的燈的編號( k<= n <= 1000)。 範例輸入: 7 3 範例輸出: 1 5 6 7 1 2 3 4 5 6 7 1 2 3

3-2 開燈問題 if(j%i==0) a[j] = !a[j]; 解析:用 a[1], a[2], a[3], …, a[n] 表示編號為1,2,3,…,n的燈是否開著。 #include <stdio.h> #include <string.h> #define maxn 1010 int a[maxn]; int main() { int n, k; memset(a, 0, sizeof(a)); scanf("%d%d", &n, &k); for (int i=1; i<=k; i++) for (int j=1; j<=n; j++) if(j%i==0) a[j] = !a[j]; for (int i=1; i<=n; i++) if (a[i]) printf("%d", i); printf("\n"); return 0; } 1 2 3 4 5 6 7 1 2 3 3-2 開燈問題

#include <stdio. h> #include <string #include <stdio.h> #include <string.h> #define maxn 1010 int a[maxn]; int main() { int n, k, first = 1; memset(a, 0, sizeof(a)); scanf("%d%d", &n, &k); for (int i=1; i<=k; i++) for (int j=1; j<=n; j++) if(j%i==0) a[j] = !a[j]; for (int i=1; i<=n; i++) if (a[i]) { if (first) first = 0; else printf(" "); //避免多餘空格 設置一個旗標變數 first printf("%d", i); } printf("\n"); return 0; } 1 2 3 4 5 6 7 1 2 3 3-2 開燈問題

陣列與字串競賽題 char c; c = getchar(); putchar(c); char s[20]; scanf("%s", s); printf("%s", s);

例題3-1 TeX中的引號(Tex Quotes, Uva 272) TeX 是一種由 Donald Knuth 所發展出的一套文書排版軟體。這套軟體可以將原始文件檔加上一些像字型等型態後,轉成一份很漂亮的文件。而一份漂亮的文件是需要用 `` 和 " 來把別人說的話給「引」出來,而不是用大部份鍵盤上有的 " 。 如果原始文件檔內容是: "To be or not to be," quoth the bard, "that is the question." 我們需要把原始文件變成這個樣子: ``To be or not to be,'' quoth the bard, ``that is the question.''

TeX中的引號(Tex Quotes, Uva 272) "To be or not to be," quoth the bard, "that is the question." ``To be or not to be,'' quoth the bard, ``that is the question.'‘ 關鍵: 如何判斷是左引號還是右引號 如何輸入字串

TeX中的引號(Tex Quotes, Uva 272) // UVa272 Tex Quotes // Rujia Liu #include<stdio.h> int main() { int c, q = 1; while((c = getchar()) != EOF) { if(c == '"') { printf("%s", q ? "``" : "''"); q = !q; } else printf("%c", c); } return 0;

TeX中的引號(Tex Quotes, Uva 272) if(c == '"') { printf("%s", q ? "``" : "''"); q = !q; } else printf("%c", c); if(c == '"'){ printf("%s", q ? "``" : "''"); q = !q; } else printf("%c", c); Hint: q 為旗標變數 q = 1 !q = 0 q = !q (正反正反…)

例題3-2 WERTYU (UVa10082) 打字時一個常見的錯誤就是沒有把手放在正確位置,而是偏右邊一個位置。所以會發生Q被打成W,J被打成K等等的情況。你的任務就是要把打錯的字修正回來。 範例輸入 O S, GOMR YPFSU/ URD. ,U [JPMR MI,NRT OD 8346333 範例輸出 I AM FINE TODAY. YES, MY PHONE NUMBER IS 7235222

WERTYU (UVa10082) #include<stdio.h> // UVa10082 WERTYU // Rujia Liu #include<stdio.h> char s[] = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./"; int main() { int i, c; while((c = getchar()) != EOF) { for (i=1; s[i] && s[i]!=c; i++); // 找錯位之後的字元在常量表中的位置 if (s[i]) putchar(s[i-1]); // 如果找到,則輸出它的前一個字元 else putchar(c); } return 0; WERTYU (UVa10082)

例題3-3 迴文(Palindromes, UVa401) 迴文的定義為正向,反向讀到的字串均相同. 如:abba , abcba ... 等就是迴文 請判斷一個字串(長度 < 1000)是否是一個迴文? 範例輸入 : abba Abcd 範例輸出 : yes no

迴文 #include<stdio.h> #include<string.h> int main() { char s[30]; while(scanf("%s", s) == 1) int len = strlen(s); int p = 1; for(int i = 0; i < (len+1)/2; i++) if (s[i] != s[len-1-i]) p = 0; // 不是回文串 break; } if (p) printf("yes\n"); else printf("no\n"); return 0; 迴文

例題3-4 猜數字遊戲提示(Master-Mind Hints, Uva 340) 實現一個經典"猜數字"游戲。 給定答案序列和用戶猜的序列,統計有多少數字位置正確(A),有多少數字在兩個序列都出現過但位置不對(B)。 輸入包含多組數據。 每組輸入第一行爲序列長度n, 第二行是答案序列,接下來是若干猜測序列。 猜測序列全0時該組數據結束。 n=0時輸入結束。

例題3-4 猜數字遊戲提示(Master-Mind Hints, Uva 340) 範例輸入: 4 1 3 5 5 1 1 2 3 4 3 3 5 6 5 5 1 6 1 3 5 0 0 0 0 10 1 2 2 2 4 5 6 6 6 9 1 2 3 4 5 6 7 8 9 1 1 1 2 2 3 3 4 4 5 5 1 2 1 3 1 5 1 6 1 9 1 2 2 5 5 5 6 6 6 7 0 0 0 0 0 0 0 0 0 0 範例輸出: Game 1: (1,1) (2,0) (1,2) (4,0) Game 2: (2,4) (3,2) (5,0) (7,0)

// UVa340 Master-Mind Hints // Rujia Liu #include<stdio // UVa340 Master-Mind Hints // Rujia Liu #include<stdio.h> #define maxn 1000 + 10 int main() { int n, a[maxn], b[maxn]; int kase = 0; while(scanf("%d", &n) == 1 && n) { // n=0時輸入結束 printf("Game %d:\n", ++kase); for(int i = 0; i < n; i++) scanf("%d", &a[i]); for(;;) { int A = 0, B = 0; for(int i = 0; i < n; i++) { scanf("%d", &b[i]); if(a[i] == b[i]) A++; } if(b[0] == 0) break; // 正常的猜測序列不會有0,所以只判斷第一個數是否爲0即可 for(int d = 1; d <= 9; d++) { int c1 = 0, c2 = 0; // 統計數字d在答案序列和猜測序列中各出現多少次 if(a[i] == d) c1++; if(b[i] == d) c2++; if(c1 < c2) B += c1; else B += c2; printf(" (%d,%d)\n", A, B-A); return 0; 猜數字遊戲提示

習題3-1 得分(Uva 1585) 列出一個由O和X組成的字串(長度為1~80),統計得分。每個O的得分為目前連續出現的O的個數,X的得分為0。例如: OOXXOXXOOO的得分為 1+2+0+0+1+0+1+0+0+1+2+3

習題3-2 分子量(Uva 1586) 列出一種物質的分子式(不帶括弧),求分子量。 本題中的分子式只包含4種原子,分別為C, H, O, N,分子量分別為 12.01, 1.008, 16.00, 14.01 (單位:g/mol)。 例如: C6H5OH 分子量為 94.108g/mol

習題3-3 數數字( Uva 1225) 把前n (n<=10000)個整數順次寫在一起:123456789101112…數一數,0~9各出現多少次。 輸出10個整數,分別是0,1,2…9出現的次數。

習題3-4 週期串(Uva 455) 如果一個字串可以由某個長度為k的字串重複多次得到,則稱該串以 k 為週期。 例如,abcabcabcabc以3為週期(注意,它也以6、12為週期) 輸入一個長度不超過80的字串,輸出其最小週期。

習題3-5 Puzzle UVa227 有一個55的網格,其中恰好有一個格子是空的,其他格子各有一個字母,一共有四種指令:A,B,L,R,分別表示把空格上、下、左、右的相鄰字母移到空格中。輸入初始網格和指令序列(分別以數字0結束),輸出指令執行完畢後的網格。如果有非法指令,應輸出"This puzzle has no final configuration.",例如,圖執行ARRBBL0後,效果如圖所示

習題3-5 Puzzle UVa227 給定方格一開始的佈局及移動步驟,請輸出方格最後的形式。 INPUT 輸入會有多組測試資料,每組資料的前五列每列有五個字元,表示方格一開始的佈局,以空白字元表示空格。第六列開始為移動步驟,每個步驟一個字元,以A表示空格上面的方塊向下移動;B表示空格下面的方塊向上移動;R表示空格右邊的方塊向左移動;L表示空格左邊的方塊向右移動。注意可能會有不合法的移動方式(就算所有移步僅包含ABRL,也可能會有不合法的移步),若出現不合法的移步,則視為該組資料無解。移步可能會有許多列,並以 0 表示移步結束。當出現字元 Z 表示測試資料結束。 OUTPUT 請在每組測試資料輸出資料編號(Puzzle #1, Puzzle #2...),若無解請輸出"This puzzle has no final configuration.",否則請輸出方塊最後的佈局,每列的字母以一個空白字元隔開,請參考範列輸出。 請每組輸出之間以一列空行隔開。

習題3-5 Puzzle UVa227 SAMPLE INPUT SAMPLE OUTPUT Puzzle #1: T R G S J XDOKI M VLN WPABE UQHCF ARRBBL0 ABCDE FGHIJ KLMNO PQRS TUVWX AAA LLLL0 AAAAABBRRRLL0 Z SAMPLE OUTPUT Puzzle #1: T R G S J X O K L I M D V B N W P A E U Q H C F Puzzle #2: A B C D F G H I E K L M N J P Q R S O T U V W X Puzzle #3: This puzzle has no final configuration.

習題3-6 Crossword Answers, Uva 232 輸入一個r行c列(1≤r, c≤10)的網格,黑格用“*”表示,每個白格都填有一個字母。如果一個白格的左邊相鄰位置或者上邊相鄰位置沒有白格(可能是黑格,也可能出了網格邊界),則稱這個白格是一個起始格。 首先把所有起始格按照從上到下、從左到右的順序編號爲1,2,3,…。 接下來要找出所有橫向單詞(Across)。這些單詞必須從一個起始格開始,向右延伸到一個黑格的左邊或者整個網格的最右列。最後找出所有竪向單詞(Down)。這些單詞必須從一個起始格開始,向下延伸到一個黑格的上邊或者整個網格的最下行。

習題3-6 Crossword Answers, Uva 232 分析: 首先搜索起始格並依次打標記。以數組a,b記錄橫縱坐標資料,數組u,w記錄橫向起始格序列與縱向起始格序列。 處理橫向單詞時依次訪問u數組記錄未訪問過的點(其橫縱坐標已由a,b數組記錄),並把已訪問過的點標記以避免重複訪問。縱向單詞亦然。 由于此前爲避免重複訪問已對u數組進行過修改,所以特意使用w數組。

習題3-7 DNA序列(UVa1368) 給定m個長度均爲n的DNA序列,求一個DNA序列,使其到所有序列的總hamming距離儘量小 兩個等長字串的Hamming distance等於字元不同的位置個數。例如:ACGT和GCGA的Hamming distance 為2(左數第1、4個字元不同) 輸入整數m和n(4<=m<=50, 4<=n<=1000),以及m個長度為n的DNA序列(只包含字母A, C, G, T). 輸出到m個序列的Hamming distance和最小的DNA序列和對應的距離。 ,如有多解,輸出最小解。

習題3-7 DNA序列(UVa1368) Sample Input Sample Output TAAGATAC 7 ACGTACGTAA 5 8 TATGATAC TAAGCTAC AAAGATCC TGAGATAC TAAGATGT 4 10 ACGTACGTAC CCGTACGTAG GCGTACGTAT TCGTACGTAA 6 10 ATGTTACCAT AAGTTACGAT AACAAAGCAA AAGTTACCTT AAGTTACCAA TACTTACCAA Sample Output TAAGATAC 7 ACGTACGTAA 6 AAGTTACCAA 12

習題3-8 循環小數(UVa202) Repeating Decimals 輸入整數a和b (0<=a<=3000, 1<=b<=3000)。 輸出a/b的循環小數表示以及循環節長度。 例如:a=5, b=43 小數表示為0.(116279069767441860465), 循環節為 21

習題3-9 子序列 All in All, Uva 10340 輸入兩個字串s和t,判斷是否可以從t中刪除0個或多個子元(其他字元順序不變),得到字串s。 例如:abcde 可以得到bce, 但無法得到dc

習題3-10 盒子 Box, Uva1587 給定6個矩形的長和寬wi 和 hi (1<wi, hi<=1000). 判斷它們能否構成長方體的6個面。

Summary 陣列和字串往往意味著大資料量,處理大資料量時經常遇到「存取非法記憶體」的錯誤。 適當把陣列空間定義得較大。 陣列大小可以用sizeof取得。 字元編碼與正確使用字串是非常重要的。

Code in the book https://github.com/aoapc-book/aoapc-bac2nd/tree/master/ch3

Day3: 函數與遞迴 學會定義區域變數與全域變數 自定函數與結構 函數呼叫與參數傳遞 理解遞迴定義與遞迴函數 熟悉Stack segment,了解stack overflow的常見原因 例題:Uva1339, 489, 133, 213, 512, 12412

自訂函數 計算兩點歐幾里得距離的函數 double dist(double x1, double y1, double x2, double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); }

自訂結構 typedef struct 計算兩點歐幾里得距離的函數 typedef struct { double x,y;} Point; double dist(Point a, Point b) { return hypot(a.x-b.x, a.y-b.y); } double hypot(double dx, double dy) { return sqrt(dx*dx-dy*dy); }

》計算組合數 編寫函數,參數是兩個非負整數n和m 傳回組合數結果 其中,m<=n<=25m C(n, m) = n! / ((n − m)! × m!)

編寫求 n! 的函數 long long factorial(int n){ long long m=1; for (int i=1; i<=n; i++) m *= i; return m; }

C(n, m) = n! / ((n − m)! × m!) long long C(int n, int m) { long long factorial(int n){ long long m=1; for (int i=1; i<=n; i++) m *= i; return m; } long long C(int n, int m) { return factorial(n) / (factorial(n-m)*factorial(m));

別忘了測試 n=25, m=12時,答案為5200300。 n=21, m=1 答案為? 即使最終答案在我們選擇的資料型別內,計算的中間結果仍可能溢位。

對複雜的運算式進行簡化 減少計算量(約分)、避免中間結果溢出 long long C(int n, int m){ if (m < n-m) m = n-m; long long ans = 1; for (int i=m+1; i<=n; i++) ans *= i; for (int i = 1; i<=n-m; i++) ans /= i; return ans; }

》質數判定 編寫一函數,參數是一個正整數n。如果n是質數,返回1,否則返回0。

is_prime (bug) int is_prime(int n) { for (int i=2; i*i <=n ; i++) if (n%i == 0) return 0; return 1; } 思考why: n = 1 n 很大

is_prime (正確) int is_prime(int n) { if (n<=1) return 0; int m = floor(sqrt(n) + 0.5); for (int i=2; i<=m ; i++) if (n%i == 0) return 0; return 1; } 思考why: m 為何不為 sqrt(n) 即可?

》兩數交換 swap() – 三變數交換 呼叫函數時的參數為實際參數(Argument)。 定義函數時的參數為形式參數(Parameter)。 函數內部的變數為區域變數(local variable)。 main()函數以外的變數為全域變數(global variable) 思考以下程式執行結果: #include <stdio.h> void swap(int a, int b){ int t=a; a=b; b=t; } int main(){ int a = 3, b=4; swap(a,b); printf("%d %d\n", a,b); return 0;

》swap() 以指標當作參數 思考以下程式執行結果: #include <stdio.h> void swap(int* a, int* b){ int t=*a; *a=*b; *b=t; } int main(){ int a = 3, b=4; swap(&a,&b); printf("%d %d\n", a,b); return 0; int* a; 整數指標的宣告 *a 為 a 指向的變數值 &a 為a 的位址

》陣列作為參數與返回值 計算陣列元素和 (傳陣列起始位址與陣列大小) int sum(int* a, int n) { int ans = 0; for (int i = 0; i<n; i++) ans +=a[i]; return ans; } int main() { int a[] = {1,2,3,4}; printf(" %d\n ", sum(a,4)}; return 0; } 若改計算 sum(a+1,3) 答案為何?

》遞迴函數 Recursive function f(n) = n! = n * f(n-1) f(0)=1 f(n) = f(n-1)*n #include <stdio.h> int f(int n){ if (n==0) return 1; else return f(n-1)*n; } 問: f(3) = ? f(3) 會如何呼叫堆疊

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

APCS1050305

練習題:UVa100 - The 3n+1 考慮以下的演算法: 輸入 n 印出 n 如果 n = 1 結束 GOTO 2 例如輸入 22, 得到的數列: 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 據推測此演算法對任何整數而言會終止 (當列印出 1 的時候)。雖然此演算法很簡單,但以上的推測是否真實卻無法知道。然而對所有的n ( 0 < n < 1,000,000 )來說,以上的推測已經被驗證是正確的。

練習題:UVa100 - The 3n+1 給一個輸入 n ,透過以上的演算法我們可以得到一個數列(1作為結尾)。此數列的長度稱為n的cycle-length。上面提到的例子, 22 的 cycle length為 16. 問題來了:對任2個整數i,j我們想要知道介於i,j(包含i,j)之間的數所產生的數列中最大的 cycle length 是多少。 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=36

Day4:搜尋、排序、堆疊、佇列 熟悉C++版競賽程式框架 熟練並掌握string 與 stringstream 熟練STL中的排序與檢索等相關函數 熟練STL中的vector容器 理解堆疊、佇列與優先佇列的概念 掌握亂數產生方法,自行設計測資 UVa 10474, 101, 136, 221

Day5:資料結構基礎 Stack, queue, 運算式解析 二元樹與走訪 圖的DFS與BFS 拓撲排序演算法、尤拉迴路 Uva 514, 10305