- Function
- Programming
- 7-1 厘米換算英尺英寸 (15 分)
- 7-2 然后是幾點 (15 分)
- 7-3 逆序的三位數 (10 分)
- 7-4 BCD解密 (10 分)
- 7-5 表格輸出 (5 分)
- 7-6 混合類型數據格式化輸入 (5 分)
- 7-7 12-24小時制 (15 分)
- 7-8 超速判斷 (10 分)
- 7-9 用天平找小球 (10 分)
- 7-10 計算工資 (15 分)
- 7-11 分段計算居民水費 (10 分)
- 7-12 兩個數的簡單計算器 (10 分)
- 7-13 日K蠟燭圖 (15 分)
- 7-14 求整數段和 (15 分)
- 7-15 計算圓周率 (15 分)
- 7-16 求符合給定條件的整數集 (15 分)
- 7-17 爬動的蠕蟲 (15 分)
- 7-18 二分法求多項式單根 (20 分)
- 7-19 支票面額 (15 分)
- 7-20 打印九九口訣表 (15 分)
- 7-21 求特殊方程的正整數解 (15 分)
- 7-22 龜兔賽跑 (20 分)
- 7-23 幣值轉換 (20 分)
- 7-24 約分最簡分式 (15 分)
- 7-25 念數字 (15 分)
- 7-26 單詞長度 (15 分)
- 7-27 冒泡法排序 (20 分)
- 7-28 猴子選大王 (20 分)
- 7-29 刪除字符串中的子串 (20 分)
- 7-30 字符串的冒泡排序 (20 分)
- 7-31 字符串循環左移 (20 分)
- 7-32 說反話-加強版 (20 分)
- 7-33 有理數加法 (15 分)
- 7-34 通訊錄的錄入與顯示 (10 分)
- 7-35 有理數均值 (20 分)
- 7-36 復數四則運算 (15 分)
- 7-37 整數分解為若干項之和 (20 分)
- 7-38 數列求和-加強版 (20 分)
- conclusion
Memory Dot 我的個人博客,歡迎來玩。
Function
Link: PTA
6-1 簡單輸出整數 (10 分)
本題要求實現一個函數,對給定的正整數N,打印從1到N的全部正整數。
void PrintN ( int N ){
for(int i = 1; i<=N; i++)
printf("%d\n",i);
}
思路:
題目很簡單但是試了好多次才通過,原因是把main函數和PrintN一起提交了,
事實上只用提交自己編寫的PrintN函數就可以了,不用提交main函數。
6-2 多項式求值 (15 分)
本題要求實現一個函數,計算階數為n,系數為a[0] ... a[n]的多項式在x點的值。
double f( int n, double a[], double x ){
double sum;
double x0 = 1; //x0必為 1
for (int i=0; i <= n; i++){
if (i == 0);//i = 0即是x0 = 1,無操作
else x0 *= x; //隨着循環逐個疊加x的次冪
sum += a[i] * x0;//求和
}
return sum;
}
思路:
一開始的思路用了2個for循環,提交后提示復雜度O(n^2)不行。於是,github里查起答案:x0可以在1個循環里逐個疊加
6-3 簡單求和 (10 分)
本題要求實現一個函數,求給定的N個整數的和。
int Sum ( int List[], int N ){
int sum = 0;
for(int j = 0; j<N; j++)
sum += List[j];
return sum;
}
思路:
很簡單的一道題,但是還是提交了幾次。原因是:sum、j必須的賦初值0。PTA里,系統不會自動賦值0。
6-4 求自定類型元素的平均 (10 分)
本題要求實現一個函數,求N個集合元素S[]的平均值,其中集合元素的類型為自定義的ElementType。
ElementType Average( ElementType S[], int N ){
ElementType sum = 0;
for(int i = 0; i < N; i++){
sum += S[i];
}
return sum/(ElementType)N; //N原來是int型,要強制轉換為ElementType
}
思路:
被除的N要強制轉換為ElementType,讓結果輸出為浮點數
6-5 求自定類型元素的最大值 (10 分)
本題要求實現一個函數,求N個集合元素S[]的平均值,其中集合元素的類型為自定義的ElementType。
ElementType Max( ElementType S[], int N ){
ElementType max = S[0];
for(int i = 0; i < N; i++){
max = max > S[i] ? max : S[i];
}
return max;
}
思路:
要額外考慮到max負數的情況,故max初值不能賦值0,要賦值S[0
6-6 求單鏈表結點的階乘和 (15 分)
本題要求實現一個函數,求單鏈表L
結點的階乘和。這里默認所有結點的值非負,且題目保證結果在int
范圍內
int FactorialSum( List L ){ //return語句,輸出輸出!!
int sum = 0;
int num;
while (L != NULL){// L-Next指向NULL時,會把其地址給L,所以得判斷L的地址
for (num = 1 ;L->Data > 0 ;L->Data--)
num *= L->Data;
sum += num;
L = L->Next;
}
return sum;
}
思路:
一開始運用時,一直在對L->Data
重復賦值,導致這道題思路錯誤。而后,引入num
才計算出來。目前會經常忘記return
語句,得讓自己多注意。
6-7 統計某類完全平方數 (20 分)
本題要求實現一個函數,判斷任一給定整數N
是否滿足條件:它是完全平方數,又至少有兩位數字相同,如144、676
等。
int IsTheNumber ( const int N )
{
int res = N; //讓N可以改變,因為N原來是const
int num[10] = {0};//存放0 ~ 9的計數值
if((int)sqrt(N) == sqrt(N)){ //或者用:sqrt(N) * sqrt(N) == N,來判斷是否為完全平方數
while(res != 0){
num[res % 10] ++;//對0 ~ 9某個計數
res /= 10;//從十位、百位...開始逐個提取
}
for (int i = 0; i < 10; i ++ ){
if(num[i] > 1) return 1;//0 ~ 9某個計數值大於等於2即該數符合要求
}
}
return 0;
}
思路:
用數組num[10]
分別計數0 ~ 9
,具體要使用取余(%10)
,除法(/10)
來計數、提取數值
6-8 簡單階乘計算 (10 分)
其中N是用戶傳入的參數,其值不超過12
。如果N
是非負整數,則該函數必須返回N
的階乘,否則返回0
。
int Factorial( const int N ){
int i;
int fac = 1;
if (N < 0) return 0;
else
for(i = 1; i <= N; i++){
fac *= i;
}
return fac;
}
思路:
本題沒有考慮N > 12
的情況,即超出32位Tmax
的情況。6-10會考慮。
6-9 統計個位數字 (15 分)
本題要求實現一個函數,可統計任一整數中某個位數出現的次數。例如-21252
中,2
出現了3
次,則該函數應該返回3
。
int Count_Digit ( const int N, const int D ){
int n = N;
int num[10] = {0};
if (n < 0) n = ~n+1; //負數取補碼轉為正數,但Tmin仍為Tmin,故單獨討論
if (n == 0x80000000){//Tmin =0x80000000 = -2147483648
if(D == 1 | D == 2 | D == 3 | D == 6 | D == 7) return 1;
if(D == 4) return 3;
if(D == 8) return 2;
}
if (n == 0) {// 0在下面的模塊中無法判斷,所以單獨判斷
if(D == 0) return 1;
else return 0;
}
else
while (n){ //參考6-7,提取並計數,但此模塊只適用於不是零的正整數(因為自加符號適用於正數計數)
num[n % 10]++;
n /= 10;
}
return num[D];
}
思路:
分類討論。1、n == 0x80000000
、n == 0
,注意要使用==
等價符號;2、將負數轉為正數處理。
6-10 階乘計算升級版 (20 分)
本題要求實現一個打印非負整數階乘的函數。(最大為1000!)
void Print_Factorial(const int N) {
long sum = 1;
if (N >= 0 && N <= 12) { //Tmax是9位數,12!也為9位數,所以可以直接計算
for (int i = 0; i <= N; i++) {
if (i == 0) {
sum = 1;
}
else {
sum = sum*i;
}
}
printf("%d\n", sum);
}
else if (N > 12 && N <= 1000) {//大於12不能直接計算,用數組表示
int Num[3000] = { 0 }; //確保最終結果的數組足夠大:1 ~ 9相乘最多有1*9=9位,10 ~ 99(90個兩位數)相乘最多有2*90=180位,100 ~ 999(90個三位數)相乘最多有3*900=2700位,1000是4*1=4位,總計2893,所以取整取3000位
int i, j, k, n;
k = 1; //位數
n = 0; //進位
Num[0] = 1; //將結果先初始化為1
int temp; //階乘的任一元素與臨時結果的某位的乘積結果
//計算
for (i = 2; i <= N; i++){ //開始階乘,階乘元素從2開始,因為1*2=2;模擬乘法,將臨時結果的每位與階乘元素相乘,並更新
for (j = 0; j < k; j++){ //實現乘法並提取進位值
temp = Num[j] * i + n; //相應階乘中的一項與當前所得結果的某位相乘,並加上進位
Num[j] = temp % 10; //更新結果的位上信息
n = temp / 10; //提取進位值
}
while (n != 0){ //如果有進位,更新最新位的信息,並擴展最終數值的位數(k)
Num[k] = n % 10; //新加一位,更新結果的位上信息。
k++; //位數增1
n = n / 10; //判斷還能不能進位,若能,則繼續更新;若不能,則將n置0
}
}
//輸出
for (i = k - 1; i >= 0; i--){//從最后一位開始倒着輸出
printf("%d", Num[i]);
}
printf("\n");
}
else {
printf("Invalid input\n");
}
}
思路:
大於9
位時,int
無法表示,1000!
的數值過於巨大,故采用數組Num[3000]
表示。簡述:模擬乘法,存儲進位值,根據是否有進位擴展數組。
參考:
Link:參考答案;
6-11 求自定類型元素序列的中位數 (25 分)
本題要求實現一個函數,求N
個集合元素A[]
的中位數,即序列中第⌊(N+1)/2⌋
大的元素。其中集合元素的類型為自定義的ElementType
。
ElementType Median( ElementType A[], int N )
{
int incr = N;
int i, j, k;
do{
incr = incr / 2; //確定增量
for (i = 0; i < incr; i++){ //實現分組
for (j = i + incr; j < N; j += incr){
if (A[j] < A[j - incr]){ //實現比較並交換
ElementType temp = A[j];
for (k = j - incr; k >= 0 && temp < A[k]; k -= incr){//大於兩個元素比較時使用
A[k + incr] = A[k];
}
A[k + incr] = temp;
}
}
}
} while (incr > 1);
return A[N / 2];//求N個集合元素A[]的中位數,即序列中第((N+1)/2向下取整)大的元素
}
思路:
使用希爾算法,時間復雜度為O(n^(1.3 ~ 2))
。而選擇算法、冒泡算法的時間復雜度為O(n^2)
不符合題目時間要求。
參考:
Link:希爾算法java實現圖示;參考答案1;參考答案2。
6-12 判斷奇偶性 (10 分)
本題要求實現判斷給定整數奇偶性的函數。
int even( int n ){
if (n % 2) return 0;
else return 1;
}
思路:
n % 2 若有余數為偶數;若無余數即0為奇數
6-13 折半查找 (15 分)
給一個嚴格遞增數列,函數int Search_Bin(SSTable T, KeyType k)用來二分地查找k在數列中的位置。
int Search_Bin(SSTable T, KeyType k){ //題目強制要求用二分法,不能用for循環歷遍
int start = 0, end = T.length - 1, mid;
while(start <= end){
mid = (start + end)/2;
if(T.R[mid].key == k) return mid;//T.R[].key范圍為T.R[1].key ~ T.R[end].key
else if(T.R[mid].key > k) end = mid - 1; //若k值小於mid元素,則mid在遞增數列左邊,所以對end取值為mid - 1縮小范圍於遞增數列左邊
else start = mid + 1;//若k值大於mid元素,則mid在遞增數列右邊,所以對start取值為mid + 1縮小范圍於遞增數列右邊
}
return 0;
}
思路:
雖然沒學過c++
,但此函數幾乎完全用c
寫。除了特殊的數據元素表示。簡述:首尾下標相加除以2
確定中位數下標mid
,然后根據中位數值與首尾數值的大小比較縮小范圍。(此處的中位數不是嚴格意義上的中位數,若start + end
為奇數,則會向下取整)
函數部分完成時間:2021.9.22
Programming
7-1 厘米換算英尺英寸 (15 分)
如果已知英制長度的英尺foot
和英寸inch
的值,那么對應的米是(foot+inch/12)×0.3048
。現在,如果用戶輸入的是厘米數,那么對應英制長度的英尺和英寸是多少呢?別忘了1
英尺等於12
英寸。
#include <stdio.h>
float c2f(int cm);
int getinch (int cm);
int main(){
int cm;
scanf("%d", &cm);
printf("%d %d", (int)c2f(cm), getinch(cm));
return 0;
}
float c2f (int cm){
float m = cm / 100.0; //100必須是float即100.0,否則cm / 100為int/int是整型輸出,直接按float輸出,會輸出0
float foot = m / 0.3048;//14 ~ 15也可以寫成 float m = cm / 30.48
return foot;
}
int getinch (int cm){
return (c2f(cm) - (int)c2f(cm)) * 12; //英寸取整乘以12
}
思路:int/int
直接按float
輸出,會輸出0
。解決方案:將分子、分母任意一個值改成float
。
7-2 然后是幾點 (15 分)
有時候人們用四位數字表示一個時間,比如1106
表示 11
點零6
分。現在,你的程序要根據起始時間和流逝的時間計算出終止時間。
讀入兩個數字,第一個數字以這樣的四位數字表示當前時間,第二個數字表示分鍾數,計算當前時間經過那么多分鍾后是幾點,結果也表示為四位數字。當小時為個位數時,沒有前導的零,例如5
點30
分表示為530
;0
點 30
分表示為030
。注意,第二個數字表示的分鍾數可能超過60
,也可能是負數。
#include<stdio.h>
int main() {
int a, b, Mul60, h, min;
scanf("%d %d", &a, &b);
Mul60 = (a / 100) * 60 + (a % 100) + b; // (a / 100)取a的小時部分,並令其為60的倍數;同時(a % 100)取a的分鍾部分,最后加上b
h = Mul60 / 60; //提取小時
min = Mul60 % 60;//提取分鍾
//%d表示打印整型的,
//%2d表示把整型數據打印最低兩位,
//%02d表示把整型數據打印最低兩位,如果不足兩位,用0補齊
printf("%d%02d",h,min);
return 0;
}
思路:因為60
進制轉化為60
的倍數,並且分為h
、min
兩段輸出,注意要使用%02d
。
7-3 逆序的三位數 (10 分)
程序每次讀入一個正3
位數,然后輸出按位逆序的數字。注意:當輸入的數字含有結尾的0
時,輸出不應帶有前導的0
。比如輸入700
,輸出應該是7
。
#include<stdio.h>
void neg(int num);//逆序輸出
int main() {
int num;
scanf("%d", &num); //對於&num,num是數值,&num是地址
neg(num);
return 0;
}
void neg(int num) {
int f = num % 10; //取個位
int s = (num % 100 - f) / 10; //取十位,除10,保證轉移到個位
int t = num / 100;//取百位
if (f == 0 && s == 0) printf("%d", t);
else if (f == 0) printf("%d%d", s, t);
else printf("%d%d%d", f, s, t);//並列輸出
}
思路:用取余、除法取個、十、百位並單獨討論十位、百位都為0
;百位為0
的情況。並列輸出是解決這類題的好方法
7-4 BCD解密 (10 分)
BCD數
是用一個字節來表達兩位十進制的數,每四個比特表示一位。所以如果一個BCD數
的十六進制是0x12
,它表達的就是十進制的12
。但是小明沒學過BCD
,把所有的BCD數
都當作二進制數轉換成十進制輸出了。於是BCD
的0x12
被輸出成了十進制的18
了!
現在,你的程序要讀入這個錯誤的十進制數,然后輸出正確的十進制數。提示:你可以把18
轉換回0x12
,然后再轉換回12
。
#include<stdio.h>
void b2t(int num); //二進制轉十進制
int main() {
int num;
scanf("%d", &num);
b2t(num);
return 0;
}
void b2t(int num) {
int f = num & 0xf; //取個位
int s = num >> 4; // 取十位
if (s == 0) printf("%d", f); //單獨處理十位為0的情況
else printf("%d%d", s, f);//並列輸出
}
思路:用位級運算取個、十位,再單獨處理十位為0
的情況(因為最終是並列輸出,防止輸出兩個0
)。位級運算有時確實比數級運算方便。
7-5 表格輸出 (5 分)
本題要求編寫程序,按照規定格式輸出表格。
#include<stdio.h>
int main() {
printf("------------------------------------\n");
printf("Province Area(km2) Pop.(10K)\n");
printf("------------------------------------\n");
printf("Anhui 139600.00 6461.00\n");
printf("Beijing 16410.54 1180.70\n");
printf("Chongqing 82400.00 3144.23\n");
printf("Shanghai 6340.50 1360.26\n");
printf("Zhejiang 101800.00 4894.00\n");
printf("------------------------------------");
return 0;
}
思路:注意最后一行無需用\n
換行
7-6 混合類型數據格式化輸入 (5 分)
本題要求編寫程序,順序讀入浮點數1、整數、字符、浮點數2,再按照字符、整數、浮點數1、浮點數2的順序輸出。
#include<stdio.h>
int main() {
int i;
float f1, f2;
char c;
scanf("%f %d %c %f", &f1, &i, &c, &f2); //一開始寫成了%0.2f,但scanf()不支持帶點的格式寫法
printf("%c %d %0.2f %0.2f", c, i, f1, f2);
return 0;
}
//scanf()不支持帶點的格式寫法,可以有長度限制,但不可以有小數位數限制
//scanf(“%5f”,&f) 這樣寫可以!
//scanf(“%5.2f”,&f) 這樣寫不可以!
//scanf(“%0.2f”,&f) 這樣寫不可以!
思路:scanf()
不支持帶點的格式寫法,可以有長度限制,但不可以有小數位數限制。
7-7 12-24小時制 (15 分)
編寫一個程序,要求用戶輸入24小時制的時間,然后顯示12小時制的時間。
#include<stdio.h>
int main() {
int h, min;
char c;
scanf("%d%c%d", &h ,&c , &min);
if (24 == h) printf("0%c%d AM", c, min); //用if判斷相等,常量在前,變量在后,可以避免將==寫成=
else if (h > 12) printf("%d%c%d PM", h - 12, c , min);
else if (12 == h) printf("%d%c%d PM", h, c , min);
else printf("%d%c%d AM", h, c , min);
return 0;
}
思路:注意題目並不要求將0
輸出成00
(其實我覺得這樣更好看)
7-8 超速判斷 (10 分)
模擬交通警察的雷達測速儀。輸入汽車速度,如果速度超出60 mph,則顯示“Speeding”,否則顯示“OK”。
#include<stdio.h>
int main() {
int v;
scanf("%d", &v);
if (v > 60 ) printf("Speed: %d - speeding", v); //題目是超出60,暗示着不包括60
else printf("Speed: %d - OK", v);
return 0;
}
思路:題目是超出60
,暗示着不包括60
。
7-9 用天平找小球 (10 分)
三個球A、B、C,大小形狀相同且其中有一個球與其他球重量不同。要求找出這個不一樣的球。
#include<stdio.h>
int main() {
int A, B, C;
scanf("%d %d %d", &A, &B, &C);
if (A == B) printf("%c", 'C'); //look at the ansewer need the output is char but not numbers
if (A == C) printf("%c", 'B');
if (B == C) printf("%c", 'A');
return 0;
}
思路:the ansewer need the output is char
but not int
.
7-10 計算工資 (15 分)
某公司員工的工資計算方法如下:一周內工作時間不超過40小時,按正常工作時間計酬;超出40小時的工作時間部分,按正常工作時間報酬的1.5倍計酬。員工按進公司時間分為新職工和老職工,進公司不少於5年的員工為老職工,5年以下的為新職工。新職工的正常工資為30元/小時,老職工的正常工資為50元/小時。請按該計酬方式計算員工的工資。
#include<stdio.h>
int main() {
int p, h;
scanf("%d %d", &p ,&h);
if (p >= 5) {
if (h > 40) printf("%0.2f", 40 * 50 + 1.5 * (h - 40) * 50);
else printf("%0.2f", h * 50.0);
}
else {
if (h > 40) printf("%0.2f", 40 * 30 + 1.5 * (h - 40) * 30);
else printf("%0.2f", h * 30.0); //int * int also int, therefore, set to int * float
}
return 0;
}
思路:int * int
also int
, therefore, set to int * float
in order to make flaot
.
7-11 分段計算居民水費 (10 分)
為鼓勵居民節約用水,自來水公司采取按用水量階梯式計價的辦法,居民應交水費y(元)與月用水量x(噸)相關:當x不超過15噸時,y=4x/3;超過后,y=2.5x−17.5。請編寫程序實現水費的計算。
#include<stdio.h>
int main() {
float x;
scanf("%f", &x);
if (x <= 15) printf("%0.2f", 4 * x / 3);
if (x > 15) printf("%0.2f", 2.5 * x - 17.5);
return 0;
}
思路:the input is float
.
7-12 兩個數的簡單計算器 (10 分)
本題要求編寫一個簡單計算器程序,可根據輸入的運算符,對2個整數進行加、減、乘、除或求余運算。題目保證輸入和輸出均不超過整型范圍。
#include<stdio.h>
int main() {
int a, b;
char c;
scanf("%d %c %d", &a, &c, &b);
if(c == '+')
printf("%d", a + b);
else if(c == '-')
printf("%d", a - b);
else if(c == '*')
printf("%d", a * b);
else if(c == '/')
printf("%d", a / b);
else if(c == '%')
printf("%d", a % b);
else
printf("ERROR");
return 0;
}
思路:easy.
7-13 日K蠟燭圖 (15 分)
股票價格漲跌趨勢,常用蠟燭圖技術中的K線圖來表示,分為按日的日K線、按周的周K線、按月的月K線等。以日K線為例,每天股票價格從開盤到收盤走完一天,對應一根蠟燭小圖,要表示四個價格:開盤價格Open(早上剛剛開始開盤買賣成交的第1筆價格)、收盤價格Close(下午收盤時最后一筆成交的價格)、中間的最高價High和最低價Low。
如果Close<Open,表示為“BW-Solid”(即“實心藍白蠟燭”);如果Close>Open,表示為“R-Hollow”(即“空心紅蠟燭”);如果Open等於Close,則為“R-Cross”(即“十字紅蠟燭”)。如果Low比Open和Close低,稱為“Lower Shadow”(即“有下影線”),如果High比Open和Close高,稱為“Upper Shadow”(即“有上影線”)。請編程序,根據給定的四個價格組合,判斷當日的蠟燭是一根什么樣的蠟燭。
#include<stdio.h>
int main() {
int Open, High, Low, Close;
scanf("%f %f %f %f", &Open ,&High, &Low, &Close);
if (Close < Open) printf("BW-Solid");
else if (Close > Open) printf("R-Hollow");
else printf("R-Cross");
if (Low < Open && Low < Close && High > Open && High > Close) //attention to order about "if", two&& big that one&&
printf(" with Lower Shadow and Upper Shadow");
else if (Low < Open && Low < Close) printf(" with Lower Shadow");
else if (High > Open && High > Close) printf(" with Upper Shadow");
return 0;
}
思路:compare quantity of condition, lots quantity at first and low quantity at second and so on.
7-14 求整數段和 (15 分)
給定兩個整數A和B,輸出從A到B的所有整數以及這些數的和。
//C(GUN) pass and C(Clang) pass
#include<stdio.h>
int main() {
int A, B;
int i,j;
int sum = 0;
scanf("%d %d", &A, &B);
if ((B - A) <= 4){ //if B - A <= 4, not have a newline.
for(i = A; i <= B; i++){
printf("%5d", i);
sum += i;
}
}
else
for(i = A, j = 1; i <= B; i++, j++){
printf("%5d", i);
if ((j % 5) == 0) printf("\n");
sum += i;
}
printf("\nSum = %d", sum);
return 0;
}
//C(GUN) not pass but C(Clang) pass
#include<stdio.h>
int main() {
int A, B;
int i,j;
int sum;
scanf("%d %d", &A, &B);
for(i = A, j = 1; i <= B; i++, j++){
printf("%5d", i);
if (B - A > 4)
if ((j % 5) == 0) printf("\n"); //if B - A > 4, have a newline.
sum += i;
}
printf("\nSum = %d", sum);
return 0;
}
思路:if B - A <= 4
, not have a newline.
7-15 計算圓周率 (15 分)
根據下面關系式,求圓周率的值,直到最后一項的值小於給定閾值。
π / 2 = 1 + 1/3 + 2!/3*5 + 3!/3*5*7 + ... + n!/3*5*7*...*(2n+1)
#include<stdio.h>
int main() {
double PI = 1, up = 1, down = 1, last = 1;
double i;
double t;
scanf("%lf", &t); //"scanf" function need address(&)
for (i = 1; last >= t; i++){
up *= i;
down *= i * 2 + 1;
last = up / down;
PI += last;
}
printf("%0.6lf", 2 * PI);
return 0;
}
思路:Attention to 0!
equal 1!
, so set PI = 1
(First iteam) and set last = up / down = 1 / 3
(Second iteam) at beginning.
7-16 求符合給定條件的整數集 (15 分)
給定不超過6的正整數A,考慮從A開始的連續4個數字。請輸出所有由它們組成的無重復數字的3位數。
//法一:用循環
#include <stdio.h>
int main(){
int a, i, j, k, cnt = 0;
scanf("%d", &a);
for(i = a; i <= a+3; i++){
for(j = a; j <= a+3; j++){
if (i == j) continue;//若 (i == j)再一次執行第二個for循環
for(k = a; k <= a+3; k++){
if (i == k || j == k) continue;//若 (i == k || j == k) 再一次執行第三個for循環
cnt++;
if ((cnt % 6) == 0) //保證每行末尾無空格
printf("%d%d%d", i, j, k);
else
printf("%d%d%d ", i, j, k);
if ((cnt % 6) == 0 && cnt <= 18) printf("\n"); //最后一次不換行
}
}
}
return 0;
}
思路:i,j,k
按遞增順序分別對應四個數,第二個for保證j != i
,第三個for保證k != i && k != j
。
它們都是按遞增順序比較是否相等之后再輸出,保證了輸出是遞增的。
在輸出的每一行中,第一個for調用一次,第二個for將調用四次,第三個for將調用十八次。
//法二:暴力枚舉
#include<stdio.h>
int main() {
int a;
scanf("%d", &a);
int b = a + 1;
int c = a + 2;
int d = a + 3;
printf("%d %d %d %d %d %d\n", a*100+b*10+c, a*100+b*10+d, a*100+c*10+b, a*100+c*10+d, a*100+d*10+b, a*100+d*10+c);
printf("%d %d %d %d %d %d\n", b*100+a*10+c, b*100+a*10+d, b*100+c*10+a, b*100+c*10+d, b*100+d*10+a, b*100+d*10+c);
printf("%d %d %d %d %d %d\n", c*100+a*10+b, c*100+a*10+d, c*100+b*10+a, c*100+b*10+d, c*100+d*10+a, c*100+d*10+b);
printf("%d %d %d %d %d %d\n", d*100+a*10+b, d*100+a*10+c, d*100+b*10+a, d*100+b*10+c, d*100+c*10+a, d*100+c*10+b);
}
7-17 爬動的蠕蟲 (15 分)
一條蠕蟲長1寸,在一口深為N寸的井的底部。已知蠕蟲每1分鍾可以向上爬U寸,但必須休息1分鍾才能接着往上爬。在休息的過程中,蠕蟲又下滑了D寸。就這樣,上爬和下滑重復進行。請問,蠕蟲需要多長時間才能爬出井?
這里要求不足1分鍾按1分鍾計,並且假定只要在某次上爬過程中蠕蟲的頭部到達了井的頂部,那么蠕蟲就完成任務了。初始時,蠕蟲是趴在井底的(即高度為0)。
#include<stdio.h>
int main(){
int n,u,d;
scanf("%d%d%d",&n,&u,&d);
int t = 0,place = 0;//時間、位置初始化為0
while(1){
place += u; //向上爬
t++; //增加向上爬的時間
if(place >= n){ //如果身體爬出井或剛好頭部接觸井沿,則結束循環
printf("%d", t);
break;
}
place -= d; //向下滑
t++;//增加向下滑的時間
}
return 0;
}
思路:完全依照題意進行編程,重點是運用了增量這個概念,對時間進行遞增,對位置進行遞增和遞減。
7-18 二分法求多項式單根 (20 分)
二分法求函數根的原理為:如果連續函數f(x)在區間[a,b]的兩個端點取值異號,即f(a)f(b)<0,則它在這個區間內至少存在1個根r,即f(r)=0。
#include <stdio.h>
//f(x) = a3*x^3 + a2*x^2 + a1*x + a0
double func(double a3, double a2, double a1, double a0, double x){
return a3 *x*x*x + a2 *x*x + a1 *x +a0;
}
int main() {
double a3, a2, a1, a0, a, b, mid, func_a, func_b, func_mid;
scanf("%lf %lf %lf %lf %lf %lf", &a3, &a2, &a1, &a0, &a, &b); //why forget `&` again ?
while(b - a > 0.001){
mid = (a + b) / 2;
func_a = func(a3, a2, a1, a0, a);
func_b = func(a3, a2, a1, a0, b);
func_mid = func(a3, a2, a1, a0, mid);
if (func_a * func_b < 0){
if(func_mid == 0) {
printf("%.2f", mid); //find it have lots time, mid != func_mid
return 0;
}
else if(func_a * func_mid > 0)
//euqal (func_mid>0 && func_a>0) || (func_mid<0 && func_a<0)
a = mid;
else if(func_b * func_mid > 0)
//euqal (func_mid>0 && func_b>0) || (func_mid<0 && func_b<0)
b = mid; //x and y have the same sign equal x*y > 0
}
else if(func_a * func_b == 0){
if(func_a == 0){
printf("%.2f", a);
return 0;
}
else if(func_b == 0){
printf("%.2f", b);
return 0;
}
}
}
printf("%.2f", (a + b) / 2);
return 0;
}
//segmentation fault
int* get(){
int *coef;
int i;
for(i = 0; i <= 3; i++)
scanf("%d", &coef[i]); //coef[0] ~ coef[3] order to a3 ~ a0
return coef;
}
// can't use array[], because it will segmentation fault
int *coef = get();
double func(int *coef, double x){ //f(x) = a3*x^3 + a2*x^2 + a1*x + a0
int i;
return coef[0] *x*x*x + coef[1] *x*x +coef[2] *x +coef[3];
// can't use pow() function, because it will segmentation fault
}
thoughts:
- try to submit array address to func, but
segmentation fault
. - try to use
double pow(double x , double n)
, but alsosegmentation fault
. - x and y have the same sign equal
x*y > 0
. - forget
&
again...when I no pay attention to it. mid != func_mid
! ! ! !
7-19 支票面額 (15 分)
一個采購員去銀行兌換一張y元f分的支票,結果出納員錯給了f元y分。采購員用去了n分之后才發覺有錯,於是清點了余額尚有2y元2f分,問該支票面額是多少?
#include<stdio.h>
int main(){
int y, f, n;
int i = 0; //支票面額從0開始
scanf("%d", &n);
while(i <= 10000){ //題目應給出支票面額的取值范圍,否則會超時
y = i / 100;
f = i % 100;
if (f*100 + y - n == 2*y*100 + 2*f){
printf("%d.%d", y, f);
return 0; //跳出循環,並且結束函數
}
i++;
}
printf("No Solution");
return 0;
}
思路:完全依照題意進行編程,思路上按照題意來,然后逐個解決。我是將輸出結果看成四位數,然后分別取前兩位,后兩位。f*100 + y - n == 2*y*100 + 2*f
其實是對“結果出納員錯給了f元y分。采購員用去了n分之后才發覺有錯,於是清點了余額尚有2y元2f分”的數學表示。注意,return 0
可以不止寫一條,只要滿足要求。
7-20 打印九九口訣表 (15 分)
下面是一個完整的的下三角九九口訣表:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
本題要求對任意給定的一位正整數N
,輸出從1*1
到N*N
的部分口訣表。
#include<stdio.h>
int main(){
int i, j, n;
scanf("%d",&n);
for(i = 1; i <= n; i++)
for(j = 1; j <= i; j++){
if (j*i <= 9 ) printf("%d*%d=%d ", j, i, j*i);
else printf("%d*%d=%d ", j, i, j*i);
if(j == i) printf("\n");
}
return 0;
}
思路:注意輸出格式,左對齊,等式右端包括數值一共占4
位。
7-21 求特殊方程的正整數解 (15 分)
本題要求對任意給定的正整數N,求方程X2+*Y*2=N的全部正整數解。
//個人解法一
#include <stdio.h>
int main() {
int i, j, n, flag = 0, a[10], b[10];
scanf("%d", &n); //scanf的輸入是存在地址上的
for(i = 1; i <= 100; i++)
for(j = 1; j <= i; j++){
if (i*i + j*j == n) {
a[flag] = j;
b[flag] = i;
flag++;
}
// else
// continue;
}
if(!flag)
printf("No Solution");
else
for(i = flag - 1; i >= 0; i--)
printf("%d %d\n", a[i], b[i]);
return 0;
}
//參考解法二
#include<stdio.h>
int main() {
int n;
scanf("%d", &n);
int i, j, flag=1;
for(i=1; i<=100; i++)
for(j=1; j<=100; j++)
if(i*i + j*j == n && i < j){
printf("%d %d\n",i,j);
flag=0;
}
if(flag) printf("No Solution");
return 0;
}
思路:個人解法中,使用數組使得x<=y
,但過於繁瑣了,不如參考解法中的i,j共同遍歷,滿足i < j
即可。同時需要注意到題目要求是正整數求解,也就是說不包括0
和負數。
7-22 龜兔賽跑 (20 分)
烏龜與兔子進行賽跑,跑場是一個矩型跑道,跑道邊可以隨地進行休息。烏龜每分鍾可以前進3米,兔子每分鍾前進9米;兔子嫌烏龜跑得慢,覺得肯定能跑贏烏龜,於是,每跑10分鍾回頭看一下烏龜,若發現自己超過烏龜,就在路邊休息,每次休息30分鍾,否則繼續跑10分鍾;而烏龜非常努力,一直跑,不休息。假定烏龜與兔子在同一起點同一時刻開始起跑,請問T分鍾后烏龜和兔子誰跑得快?
#include<stdio.h>
int main(){
int rab_speed = 9, tur_speed = 3;
int rabbit = 0, turtle = 0;
int T, rab_sleep = -1, rab_time = 10;
/*rab_sleep = -1 because line 17 of 'rab_sleep != 0' and line 22 of 'rab_sleep-- == 0'
rabbit can't sleep at bgain and We can't every minutes reset 'rab_time = 10'
*/
scanf("%d", &T);
while(T--){// count down T
turtle += tur_speed;
if(rab_time-- > 0)// count down 10_min
rabbit += rab_speed;
if(rab_time == 0){ // Execute when the 10 min countdown is over
/* rabbit above turtle and rabbit not sleep */
if(rabbit > turtle && rab_sleep != 0)
rab_sleep = 30;
else
rab_time = 10;
}
if(rab_sleep-- == 0)// count down sleep_time
rab_time = 10;
}
if(rabbit > turtle)
printf("^_^ %d", rabbit);
else if(rabbit < turtle)
printf("@_@ %d", turtle);
else
printf("-_- %d", rabbit);
return 0;
}
thought:learn using countdown design.
7-23 幣值轉換 (20 分)
輸入一個整數(位數不超過9位)代表一個人民幣值(單位為元),請轉換成財務要求的大寫中文格式。如23108元,轉換后變成“貳萬叄仟壹百零捌”元。為了簡化輸出,用小寫英文字母a-j順序代表大寫數字0-9,用S、B、Q、W、Y分別代表拾、百、仟、萬、億。於是23108元應被轉換輸出為“cWdQbBai”元。
#include<stdio.h>
int main()
{
int num, temp;
int count = 0;
int dec;
int i, j;
int flag = 0;
int data[10];
scanf("%d",&num);
temp = num;
if(num == 0){//單個0時輸出
printf("a");
}
while(num != 0){//將數字分解,並存入數組data[]中
i = num % 10; //取最低一位
data[count] = i;
count++;
num = num / 10; //截掉最低位,更新num
}
dec = count + 1; //之所以要+1是因為每次使用前要自減(line23)
for(j = count-1; j >= 0; j--){//j = count-1,是因為while循環結束時,count還要自加一次,減去1以抵消這一次自加
dec--;// dec表示數字分解后,總共分解出多少個數字
if(temp > 10000 && data[j] == 0 && data[j-1] == 0 && data[1] != 0 && flag == 0){
//超過一萬,中間連續多個0解決方法
//原理是要滿足:num大於一萬,而且至少有兩個連續的0,以及num的從右往左數,第2個數為不為0,即data[1] != 0.
flag++; //最后要用flag保證滿足時只輸出一次'W'。
printf("W");
}
if(data[j] == 0 && data[j-1] == 0){//只滿足至少有兩個連續的0,則重新開始循環
continue;
}
switch(data[j]){//數字轉字母
case 0:
printf("a");
break;
case 1:
printf("b");
break;
case 2:
printf("c");
break;
case 3:
printf("d");
break;
case 4:
printf("e");
break;
case 5:
printf("f");
break;
case 6:
printf("g");
break;
case 7:
printf("h");
break;
case 8:
printf("i");
break;
case 9:
printf("j");
break;
}
if(data[j] != 0){//數字轉單位
switch(dec)//直到用完分解的數才結束
{
case 1:
break;
case 2:
printf("S");
break;
case 3:
printf("B");
break;
case 4:
printf("Q");
break;
case 5:
printf("W");
break;
case 6:
printf("S");
break;
case 7:
printf("B");
break;
case 8:
printf("Q");
break;
case 9:
printf("Y");
break;
}
}
}
return 0;
}
思路:從最低位分解數字,之后要考慮中間連續為0時,是否有過萬。
7-24 約分最簡分式 (15 分)
分數可以表示為分子/分母
的形式。編寫一個程序,要求用戶輸入一個分數,然后將其約分為最簡分式。最簡分式是指分子和分母不具有可以約分的成分了。如6/12可以被約分為1/2。當分子大於分母時,不需要表達為整數又分數的形式,即11/8還是11/8;而當分子分母相等時,仍然表達為1/1的分數形式。
#include <stdio.h>
int main(){
int num, den, x, x_max, com_fac_max;
char sem;
scanf("%d%c%d", &num, &sem, &den);
x_max = num < den ? num : den; //smaller number as x_max
for(x = 1; x <= x_max; x++)//find 'com_fac_max'
if (num % x == 0 && den % x == 0)
com_fac_max = x; //updata 'com_fac_max'
printf("%d%c%d", num / com_fac_max, sem, den / com_fac_max);
return 0;
}
though: traveral 1 ~ x_max
to find com_fac_max
(maxinum of common factor).
還找到了一個簡潔優雅的遞歸函數來求最大公因數:
#include <stdio.h>
int gcd(int x, int y){return y ? gcd(y, x%y) : x;}//find maxinum of common factor
int main(){
int num, den, com_fac_max;
char sem;
scanf("%d%c%d", &num, &sem, &den);
com_fac_max = gcd(num, den);
printf("%d%c%d", num / com_fac_max, sem, den / com_fac_max);
return 0;
}
7-25 念數字 (15 分)
輸入一個整數,輸出每個數字對應的拼音。當整數為負數時,先輸出fu
字。十個數字對應的拼音如下:
0: ling
1: yi
2: er
3: san
4: si
5: wu
6: liu
7: qi
8: ba
9: jiu
AC代碼:
#include <stdio.h>
int main(){
int num, cut[100], i;
scanf("%d", &num);
if (num == 0){
printf("ling");
return 0;
}
if (num < 0){
printf("fu ");
num = ~num + 1;//取補碼,即取絕對值,但對int_min = -2147483648無效
}
if (num == -2147483648){//單獨拎出來輸出
printf("fu er yi si qi si ba san liu si ba");
return 0;
}
for(i = 1; num != 0 ;i++){ //當不等於0時才執行
cut[i] = num % 10;
num /= 10; //更新num
}
i--;
while(i){
switch (cut [i]){
case 0:
printf("ling");
break;
case 1:
printf("yi");
break;
case 2:
printf("er");
break;
case 3:
printf("san");
break;
case 4:
printf("si");
break;
case 5:
printf("wu");
break;
case 6:
printf("liu");
break;
case 7:
printf("qi");
break;
case 8:
printf("ba");
break;
case 9:
printf("jiu");
break;
}
i--; //降序輸出
if (i != 0) //確保最后一個數字之后沒有空格,而其它數字之后有空格
printf(" ");
}
return 0;
}
思路:不斷分割輸入的整數,但注意for循環結束后的i,比所需的cut[i]的i值多了1,需要減去。同時輸出時是按i值降序(從大到小)輸出的。
7-26 單詞長度 (15 分)
你的程序要讀入一行文本,其中以空格分隔為若干個單詞,以.
結束。你要輸出每個單詞的長度。這里的單詞與語言無關,可以包括各種符號,比如it's
算一個單詞,長度為4。注意,行中可能出現連續的空格;最后的.
不計算在內。
#include <stdio.h>
int main (){
char c;
int flag = 0, count;
while(1){
count = 0; //set(reset) count
scanf("%c",&c); //set(reset) first character
while(c != ' ' && c != '.'){ //count and input
count++;
scanf("%c", &c);
}
if(count != 0){
flag++;
if(flag == 1) printf("%d", count); //first number
else printf(" %d", count); //other numbers
}
if(c == '.') break;
}
return 0;
}
ideas:
- Before counting, we must set(reset)
count
and the firstc
. - The format of output are one numbers:
%d
or some numbers:%d %d %d %d
, so we must setflag
.
7-27 冒泡法排序 (20 分)
將N個整數按從小到大排序的冒泡排序法是這樣工作的:從頭到尾比較相鄰兩個元素,如果前面的元素大於其緊隨的后面元素,則交換它們。通過一遍掃描,則最后一個元素必定是最大的元素。然后用同樣的方法對前N−1個元素進行第二遍掃描。依此類推,最后只需處理兩個元素,就完成了對N個數的排序。
本題要求對任意給定的K(<N),輸出掃描完第K遍后的中間結果數列。
輸入格式:
輸入在第1行中給出N和K(1≤K<N≤100),在第2行中給出N個待排序的整數,數字間以空格分隔。
輸出格式:
在一行中輸出冒泡排序法掃描完第K遍后的中間結果數列,數字間以空格分隔,但末尾不得有多余空格。
輸入樣例:
6 2
2 3 5 1 6 4
結尾無空行
輸出樣例:
2 1 3 4 5 6
結尾無空行
AC code:
#include <stdio.h>
int main(){
int N, K;
int i, j;
scanf("%d %d", &N, &K);
int num[N];
int temp, flag;
for(i = 0; i < N; i++){
scanf("%d", &num[i]);
}
for(i = 0; i < K; i++){
for(j = 1; j < N; j++){
if(num[j - 1] > num[j]){ //swap
temp = num[j];
num[j] = num[j - 1];
num[j - 1] = temp;
}
}
N--; //last number already is max, so reset `N`
}
for(i = 0; i < N+K; i++){ //use flag in order to Format
if(flag == 0)
printf("%d", num[i]);
else
printf(" %d", num[i]);
flag++;
}
return 0;
}
ideas:
- Begain using
debug
; contiune
running of models;step over
running of ''one by one''("line by line");step into
into this function, and then do this function of ''one by one'';step out
leave this function.
7-28 猴子選大王 (20 分)
一群猴子要選新猴王。新猴王的選擇方法是:讓N只候選猴子圍成一圈,從某位置起順序編號為1~N號。從第1號開始報數,每輪從1報到3,凡報到3的猴子即退出圈子,接着又從緊鄰的下一只猴子開始同樣的報數。如此不斷循環,最后剩下的一只猴子就選為猴王。請問是原來第幾號猴子當選猴王?
AC code:
#include <stdio.h>
int main(){
int N;
scanf("%d", &N);
int a[N];
int i;
for (i=0; i<N; i++)
a[i]=i+1;
int elimination = 0; //淘汰變量
int remainder = N; //剩余變量
while (remainder > 1){
for (i=0; i<N; i++){
if (a[i] == 0)
continue;
//序號為0的猴已淘汰,不計數,直接進入下一輪循環
elimination++;
if (elimination == 3){
a[i] = 0; //淘汰之后的猴子序號設為0
elimination = 0; //淘汰變量重置
remainder--; //剩余猴數減1
}
}
}
for (i=0; i<N; i++)
if (a[i] != 0)
printf("%d\n", i+1);
return 0;
}
思路:引入兩個計數變量,第一個變量作為淘汰變量,每數到3淘汰一個,重新計數;
第二個變量作為剩余變量,記錄剩余猴子數,每淘汰一個減少1,當剩余變量為1時,結束。
7-29 刪除字符串中的子串 (20 分)
輸入2個字符串S1和S2,要求刪除字符串S1中出現的所有子串S2,即結果字符串中不能包含S2。
AC code:
#include<stdio.h>
#include<string.h>
int main (){
char s1[100], s2[100], temp[100];
gets(s1);
gets(s2);
char *s1_s2; //當s1中含有s2時, s1_s2視為s1中的s2首地址
while(s1_s2 = strstr(s1, s2)){ //比對,當s1中含有s2時,執行循環(此時s1_s2為s1中的s2首地址);若s1中不含有s2,則循環結束(此時s1_s2為NULL)
strcpy(temp, s1_s2 + strlen(s2)); //s1_s2加上s2的長度用來跳過想要刪除的子串,將跳過之后的字符串復制到臨時數組
*s1_s2 = '\0'; //把s1_s2此時存放的字符變為'\0',以下一步用strcat實現拼接
strcat(s1, temp); //將臨時數組拼接在s1_s2的位置之后(即s1的第一個終止符'\0'之后)
}
puts(s1);
return 0;
}
解答二:利用string.h庫中的字符串函數解決
提示:在 C 語言中,字符串實際上是使用字符
\0
終止的一維字符數組。先來介紹要用到的字符串函數:
1、char *strstr( const char *str1, const char *str2 );
功能:用於判斷字符串str2是否是str1的子串。如果是,則該函數返回 str1字符串從 str2第一次出現的位置開始到 str1結尾的字符串;否則,返回NULL。
2、char *strcpy( char *str1, const char *str2 );
功能:復制,把從str2地址開始且含有NULL結束符的字符串復制到以str1開始的地址空間
3、char *strcat( char *str1, const char *str2 );
功能:拼接,把str2所指向的字符串(包括
\0
)復制到str1所指向的字符串后面(刪除str1原來末尾的\0
)。注意要保證str1足夠長,以容納被復制進來的*str2。注意:以上兩個函數(strcpy,strcat)中str1和str2所指內存區域不可以重疊且str1必須有足夠的空間來容納str2的字符串。因此代碼中定義了一個臨時數組。
解法參考鏈接;字符串函數參考鏈接;c語言NULL和0區別及NULL詳解
7-30 字符串的冒泡排序 (20 分)
我們已經知道了將N個整數按從小到大排序的冒泡排序法(7-27)。本題要求將此方法用於字符串序列,並對任意給定的K(<N),輸出掃描完第K遍后的中間結果序列。
AC code:
#include <stdio.h>
#include <string.h>
int main(){
int N, K;
int i, j;
scanf("%d %d", &N, &K);
char str[N][11];//using two-dimensional array so that each element is a string
char temp[11]; //if have 10 character, the 11 character is '\0'
for(i = 0; i < N; i++){
scanf("%s", &str[i]);
}
for(i = 0; i < K; i++){
for(j = 0; j < N - 1; j++){
if(strcmp(str[j], str[j+1]) > 0){ //swap
strcpy(temp, str[j]);
strcpy(str[j], str[j+1]);
strcpy(str[j+1], temp);
}
}
N--; //last strber already is max, so reset `N`
}
for(i = 0; i < N+K; i++)
printf("%s\n", str[i]);
return 0;
}
提示:在 C 語言中,字符串實際上是使用字符
\0
終止的一維字符數組。介紹string.h中的字符串函數:
- char *strcpy( char *str1, const char *str2 );
功能:復制,把從str2地址開始且含有NULL結束符的字符串復制到以str1開始的地址空間- int *strcmp( char *str1, const char *str2 );
用於比較兩個字符串並根據比較結果返回整數。若str1=str2,則返回零;若str1<str2,則返回負數;若str1>str2,則返回正數。
7-31 字符串循環左移 (20 分)
輸入一個字符串和一個非負整數N,要求將字符串循環左移N次。
輸入格式:
輸入在第1行中給出一個不超過100個字符長度的、以回車結束的非空字符串;第2行給出非負整數N。
輸出格式:
在一行中輸出循環左移N次后的字符串。
輸入樣例:
Hello World!
2
結尾無空行
輸出樣例:
llo World!He
結尾無空行
AC code:
#include <stdio.h>
#include <string.h>
int main(){
int n;
char s1[101], s2[101], temp[101];
char* s1_s2;
gets(s1);
scanf("%d", &n);
int len = strlen(s1);
if(n % len == 0){ //由於是循環左移,要考慮n是s1長度的倍數的情況
puts(s1);
return 0;
}
if(n > len){ //由於是循環左移,要考慮n大於s1長度的情況
n -= (n / len) * len;
}
strncpy(s2, s1, n);
s1_s2 = strstr(s1, s2);
strcpy(temp, s1_s2 + n);
*s1_s2 = '\0';
strcat(s1, temp);
strncat(s1, s2, n);
// puts(s1);
for(int i = 0; i < len; i++){
printf("%c", s1[i]);
}
return 0;
}
思路:又學習了兩個字符串函數;參考了7-29
,但是要區別這是循環左移;最后發現puts()函數會導致段錯誤。
提示:在 C 語言中,字符串實際上是使用字符
\0
終止的一維字符數組。介紹string.h中的字符串函數:
- char *strncpy( char *str1, const char *str2, int n );
功能:復制,把從str2地址開始且含有NULL結束符的前n個字符串復制到以str1開始的地址空間- char strncat( char *str1, const char *str2, int n );
功能:拼接,把str2所指向的字符串的前n個字符(再加一個\0
)復制到str1所指向的字符串后面(刪除str1原來末尾的\0
)。注意要保證str1足夠長,以容納被復制進來的str2
7-32 說反話-加強版 (20 分)
給定一句英語,要求你編寫程序,將句中所有單詞的順序顛倒輸出。
輸入格式:
測試輸入包含一個測試用例,在一行內給出總長度不超過500 000的字符串。字符串由若干單詞和若干空格組成,其中單詞是由英文字母(大小寫有區分)組成的字符串,單詞之間用若干個空格分開。
輸出格式:
每個測試用例的輸出占一行,輸出倒序后的句子,並且保證單詞間只有1個空格。
輸入樣例:
Hello World Here I Come
結尾無空行
輸出樣例:
Come I Here World Hello
結尾無空行
AC code:
#include<stdio.h>//標准c,沒有用c++的string,這樣首先讀取字符串就是個問題了
#define MAX 500000
int main (){
char c;//存放單獨一個字符
char t[MAX];//創建一個字符數組
int i = 0, count = 0, flag = 0;
//先處理字符串,刪除多余的空格(包括頭尾、中間的空格),形成新字符串
while ((c = getchar()) != '\n') {//getchar每次從標准輸入讀入一個字符 ,標准輸入會有'\n'???
if (c != ' ') {
flag = 1; //標記遇到單詞
t[i++] = c;
count = 0;
}
else if (count > 0) {
continue;//遇到連續兩個空格或以上用contiue跳過
}
else if (flag) {
t[i++] = c; //只有之前遇到單詞的情況下碰到空格才把這個空格寫入目標字符串
count = 1;
}
}
//刪除多余的空格,將目標字符串放入 t 中
//這里的count起了什么作用呢?
//如遇到 Hello,都存入t中,遇到第一個空格,此時count=0,flag=1,把這個空格存入t,count=1
//遇到連續兩個空格或以上用continue跳過作用,如World之后有三個空格
//開頭就是空格咋辦?啥也不操作
//倒着輸出單詞
count = 0;
int j;
for (i -= 1; i >= 0; i--) {//最后一個標號為i里面是存'\0'的,一開始要用i-=1避免輸出
if (t[i] != ' ') {
count ++; // 這里的 count 統計的是一個單詞里字母的個數
} else if (t[i] == ' ' && count > 0) {//遇到空格就輸出單詞
for (j = i+1; j <= i+count; j++) {//但注意對於單個字母而言是順序輸出,對單個單詞是倒着輸出
printf("%c", t[j]);
}
printf(" ");
count = 0;
}
}
// 還剩最后一個單詞沒輸出,因為最后一個單詞前方無空格,只完成了count++,但是遇不到空格,那么邏輯是一樣的
count--;
for (j = 0; j <= count; j++) {//輸出最后一個單詞
printf("%c", t[j]);
}
return 0;
}
思路:多使用標記,如flag, count
。Reference Linking
7-33 有理數加法 (15 分)
本題要求編寫程序,計算兩個有理數的和。
輸入格式:
輸入在一行中按照a1/b1 a2/b2
的格式給出兩個分數形式的有理數,其中分子和分母全是整形范圍內的正整數。
輸出格式:
在一行中按照a/b
的格式輸出兩個有理數的和。注意必須是該有理數的最簡分數形式,若分母為1,則只輸出分子。
輸入樣例1:
1/3 1/6
結尾無空行
輸出樣例1:
1/2
結尾無空行
輸入樣例2:
4/3 2/3
輸出樣例2:
2
AC code:
#include <stdio.h>
int gcd(int x, int y){return y ? gcd(y, x%y) : x;}//find maxinum of common factor
int main(){
int a1,a2,b1,b2;
int a,b;
scanf("%d/%d %d/%d", &a1, &b1, &a2, &b2);
if(b1 == b2){ //add
a = a1 + a2;
b = b1;
}
else{
b = b1 * b2;
a1 = a1 * b2;
a2 = a2 * b1;
a = a1 + a2;
}
if(a%b == 0) //can exact division
printf("%d", a/b);
else{ //find common factor of maximum
int com_fac_max = gcd(a, b);
printf("%d/%d", a/com_fac_max, b/com_fac_max);
}
return 0;
}
idea: refer to [7-24 約分最簡分式 ](# 7-24 約分最簡分式 (15 分))
ps: Recently, I will spend a lot of time preparing for CET6.
7-34 通訊錄的錄入與顯示 (10 分)
通訊錄中的一條記錄包含下述基本信息:朋友的姓名、出生日期、性別、固定電話號碼、移動電話號碼。 本題要求編寫程序,錄入N條記錄,並且根據要求顯示任意某條記錄。
輸入格式:
輸入在第一行給出正整數N(≤10);隨后N行,每行按照格式姓名 生日 性別 固話 手機
給出一條記錄。其中姓名
是不超過10個字符、不包含空格的非空字符串;生日按yyyy/mm/dd
的格式給出年月日;性別用M
表示“男”、F
表示“女”;固話
和手機
均為不超過15位的連續數字,前面有可能出現+
。
在通訊錄記錄輸入完成后,最后一行給出正整數K,並且隨后給出K個整數,表示要查詢的記錄編號(從0到N−1順序編號)。數字間以空格分隔。
輸出格式:
對每一條要查詢的記錄編號,在一行中按照姓名 固話 手機 性別 生日
的格式輸出該記錄。若要查詢的記錄不存在,則輸出Not Found
。
輸入樣例:
3
Chris 1984/03/10 F +86181779452 13707010007
LaoLao 1967/11/30 F 057187951100 +8618618623333
QiaoLin 1980/01/01 M 84172333 10086
2 1 7
結尾無空行
輸出樣例:
LaoLao 057187951100 +8618618623333 F 1967/11/30
Not Found
結尾無空行
AC code:
#include<stdio.h>
struct unit{
char name[11]; //10 characters + 1 '\0' = 16 char
char day[11];
char gender;
char telephone[17]; //15 numbers + 1 '\0' + 1 char of '+' = 17 char
char mobile[17];
};
int main() {
int N, K, num;
int i;
scanf("%d\n", &N);
struct unit info[N];
for(i = 0; i < N; i++){
scanf("%s %s %c %s %s", &info[i].name, &info[i].day, &info[i].gender, &info[i].telephone, &info[i].mobile);
}
scanf("\n%d", &K); // After inputing all strings, you input K
for(i = 0; i < K; i++){
scanf("%d", &num);
if(num >=0 && num < N) //num is integer so maybe < 0
printf("%s %s %s %c %s\n", info[num].name, info[num].telephone, info[num].mobile, info[num].gender, info[num].day);
else
printf("Not Found\n");
}
return 0;
}
idea: use struct
array and string %s
.
7-35 有理數均值 (20 分)
日期:21.11.8
本題要求編寫程序,計算N個有理數的平均值。
輸入格式:
輸入第一行給出正整數N(≤100);第二行中按照a1/b1 a2/b2 …
的格式給出N個分數形式的有理數,其中分子和分母全是整形范圍內的整數;如果是負數,則負號一定出現在最前面。
輸出格式:
在一行中按照a/b
的格式輸出N個有理數的平均值。注意必須是該有理數的最簡分數形式,若分母為1,則只輸出分子。
輸入樣例1:
4
1/2 1/6 3/6 -5/10
結尾無空行
輸出樣例1:
1/6
結尾無空行
輸入樣例2:
2
4/3 2/3
輸出樣例2:
1
AC code:
#include <stdio.h>
int gcd(int x, int y){return y ? gcd(y, x%y) : x;}//find maxinum of common factor
int main(){
int sum = 0, N, com_fac_max;
scanf("%d", &N);
int a[N], b[N];
for (int i = 0; i < N; i++){//每次輸入都約分防止求和時溢出
scanf("%d/%d", &a[i], &b[i]);
com_fac_max = gcd(a[i], b[i]);
a[i] = a[i] / com_fac_max;
b[i] = b[i] / com_fac_max;
}
int big, min, last_min;
if (N == 1){
min = b[0];
last_min = b[0];
}
else{ //求分母的最小公約數,按順序兩兩比較來求
big = b[0] > b[1] ? b[0] : b[1]; //如果只有兩個數,要單獨找
for (int i = 0; i < N - 1; i++){ //'i < N - 1'是因為最后一個分母是b[(N-2) + 1] = b[N-1]
big = big > b[i+1] ? big : b[i+1]; //找大的分母
for(int j = 1; j < 100; j++){
min = big * j; //用大的分母不斷線性遞增
if(min % b[i+1] == 0 && min % b[i] == 0){ //使得恰好兩個分母都能整除
last_min = min; //更新分母的最小公約數
break;
}
}
}
}
for (int i = 0; i < N; i++){//統一分母為最小公約數后,化簡分子
a[i] = last_min / b[i] * a[i];
}
for (int i = 0; i < N; i++){//分子求和
sum += a[i];
}
int down = last_min * N; //分母記得乘上數據個數,以求均值
if(sum % down == 0) //分子可以完全整除分母時,就直接除
printf("%d", sum/down);
else{ //否則再約分一次
com_fac_max = gcd(sum, down);
printf("%d/%d", sum / com_fac_max, down / com_fac_max);
}
return 0;
}
思路:
- 主要是求多個分母的最小公約數那一塊,要考慮到只有一個數、只有兩個數的邊界情況。本質上還是用for循環一個個找,使得能夠兩兩被整除。
- 報錯提示:“若不隨時化簡,則會溢出”,告訴我們要考慮到分子求和可能會溢出的情況,所以每輸入一次就化簡一次。
gcd(int x, int y)
仍舊源自 [7-24 約分最簡分式 ](# 7-24 約分最簡分式 (15 分))
7-36 復數四則運算 (15 分)
日期:21.11.22
本題要求編寫程序,計算2個復數的和、差、積、商。
輸入格式:
輸入在一行中按照a1 b1 a2 b2
的格式給出2個復數C1=a1+b1i
和C2=a2+b2i
的實部和虛部。題目保證C2不為0。
輸出格式:
分別在4行中按照(a1+b1i) 運算符 (a2+b2i) = 結果
的格式順序輸出2個復數的和、差、積、商,數字精確到小數點后1位。如果結果的實部或者虛部為0,則不輸出。如果結果為0,則輸出0.0。
輸入樣例1:
2 3.08 -2.04 5.06
結尾無空行
輸出樣例1:
(2.0+3.1i) + (-2.0+5.1i) = 8.1i
(2.0+3.1i) - (-2.0+5.1i) = 4.0-2.0i
(2.0+3.1i) * (-2.0+5.1i) = -19.7+3.8i
(2.0+3.1i) / (-2.0+5.1i) = 0.4-0.6i
結尾無空行
輸入樣例2:
1 1 -1 -1.01
輸出樣例2:
(1.0+1.0i) + (-1.0-1.0i) = 0.0
(1.0+1.0i) - (-1.0-1.0i) = 2.0+2.0i
(1.0+1.0i) * (-1.0-1.0i) = -2.0i
(1.0+1.0i) / (-1.0-1.0i) = -1.0
AC code:
#include <stdio.h>
#include <stdlib.h>
void Print_left(float a1, float b1, float a2, float b2, char c);
void Print_result(float res1, float res2);
float round(float num);
int main(){
float a1,b1,a2,b2;
scanf("%f %f %f %f", &a1, &b1, &a2, &b2);
Print_left(a1, b1, a2, b2, '+');
Print_result(round(a1 + a2), round(b1 + b2));
Print_left(a1, b1, a2, b2, '-');
Print_result(round(a1 - a2), round(b1 - b2));
Print_left(a1, b1, a2, b2, '*');
Print_result(round(a1*a2 - b1*b2), round(a1*b2 + a2*b1));
Print_left(a1, b1, a2, b2, '/');
Print_result(round((a1*a2 + b1*b2) / (a2*a2 + b2*b2)), round((-a1*b2 + a2*b1) / (a2*a2 + b2*b2)));
return 0;
}
//打印等號左邊及等號
void Print_left(float a1, float b1, float a2, float b2, char c){
if(b1 < 0 && b2 < 0)
printf("(%0.1f%0.1fi) %c (%0.1f%0.1fi) = ",a1,b1,c,a2,b2);
else if(b1 < 0)
printf("(%0.1f%0.1fi) %c (%0.1f+%0.1fi) = ",a1,b1,c,a2,b2);
else if(b2 < 0)
printf("(%0.1f+%0.1fi) %c (%0.1f%0.1fi) = ",a1,b1,c,a2,b2);
else
printf("(%0.1f+%0.1fi) %c (%0.1f+%0.1fi) = ",a1,b1,c,a2,b2);
}
//打印結果(即打印等號右邊)
void Print_result(float res1, float res2){
if(res1 == 0 && res2 == 0)
printf("0.0\n");
else if(res1 == 0)
printf("%0.1fi\n",res2);
else if(res2 == 0)
printf("%0.1f\n",res1);
else if(res2 < 0)
printf("%0.1f%0.1fi\n",res1,res2);
else
printf("%0.1f+%0.1fi\n",res1,res2);
}
//四舍五入,要區分正負數的情況
float round(float num){
if(num > 0)
num = (int)(num*10 + 0.5)/10.0;
else
num = (int)(num*10 - 0.5)/10.0;
return num;
}
思路:
- 先計算再四舍五入最后才輸出(保留一位小數),注意四舍五入要區分正負數。
- 復數乘法、除法采用數學公式即可
- 等號左右式子的格式都需要用
if
語句區分情況。
7-37 整數分解為若干項之和 (20 分)
21.12.20
將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。編程求出正整數N的所有整數分解式子。
輸入格式:
每個輸入包含一個測試用例,即正整數N (0<N≤30)。
輸出格式:
按遞增順序輸出N的所有整數分解式子。遞增順序是指:對於兩個分解序列N1={n1,n2,⋯}和N2={m1,m2,⋯},若存在i使得n1=m1,⋯,ni=mi,但是ni+1<mi+1,則N1序列必定在N*2序列之前輸出。每個式子由小到大相加,式子間用分號隔開,且每輸出4個式子后換行。
輸入樣例:
7
結尾無空行
輸出樣例:
7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7
結尾無空行
AC code:
#include<stdio.h>
int N;
int num[31]; //用數組存放划分結果
int index = -1; //數組的下標(索引),表示拆分項的個數
int sum = 0; //拆分項的累加和,若sum == N則輸出,若sum < N則放棄該遞歸,若sum < N則執行算法和遞歸
int count = 0; //統計輸出的次數,作為輔助,保證輸出格式滿足題目要求,每行最多四個式子
//以上都是全局變量
void division (int x);
int main(){
scanf("%d", &N);
division(1); //拆分項從最小正整數 == 1開始,直到滿足num[0] == sum == N
return 0;
}
void division (int x) {//拆分
//輸出部分
if (sum == N) {
count ++;
printf("%d=", N);
int j;
for (j = 0; j < index; j++)
printf("%d+", num[j]); //輸出拆分項
if (count % 4 == 0 || num[index] == N)
printf("%d\n", num[index]);
else
printf("%d;", num[index]);
return 0;
}
//算法主體
if (sum > N) {
return 0;
}
for (int i = x; i <= N; i++) { //拆分項從最小正整數 i== 1開始,注意,這里只改變某一項的數值
num[++index] = i; //在完成全1拆分后,從最后一項 i== 2開始
sum += i;
division (i);//進入遞歸
sum -= i; //放棄上一個拆分項,以便下一次重新求和
index --; //在每一個for循環中保持不變,但在進入下一個for時循環執行自減,使數組范圍變小
}
}
思路:
如圖所示,以N = 3
為例子,可以看到,一開始拆分項全都為1,而后從最后一項 i== 2
開始變化,執行這一次的for循環。總共3個黑框代表3個for循環。最后退出循環是因為只有一個division,沒有遞歸直接return回main
。
7-38 數列求和-加強版 (20 分)
日期:
21.12.21
給定某數字A(1≤A≤9)以及非負整數N(0≤N≤100000),求數列之和S=A+AA+AAA+⋯+AA⋯A(N個A)。例如A=1, N=3時,S=1+11+111=123。
輸入格式:
輸入數字A與非負整數N。
輸出格式:
輸出其N項數列之和S的值。
輸入樣例:
1 3
結尾無空行
輸出樣例:
123
結尾無空行
AC code:
#include <stdio.h>
#include <stdlib.h>
int main(){
int A = 0;
int N = 0;
scanf("%d%d", &A, &N);
int flag = 0; //是否為N+1位數的標志
int carry = 0; //臨時存放進位數值
int* num = (int*)malloc(sizeof(int) * (N + 1)); //創建動態數組指針
if (A == 0 || N == 0) //獨立“0”的特殊情況
printf("0");
else{
for (int i = 0; i < N; i++){
if (i == 0)
num[i] = A * N % 10; //個位數值
else
num[i] = (A * (N - i) % 10 + carry) % 10; //除個位以外的數值
carry = (A * (N - i) + carry) / 10; //計算進位數值
if (i == N - 1 && carry != 0){ //N+1位數存在的判斷條件
num[N] = 1;
flag = 1;
}
}
}
if (flag == 1)
for (int i = N; i >= 0; i--)
printf("%d", num[i]);
else
for (int i = N-1; i >= 0; i--)
printf("%d", num[i]);
return 0;
}
思路:
-
雙長整型也無法保存
100,000
個數值,所以用動態數組指針 -
A = 0,N = 0
是特殊情況,單獨處理 -
以計算
A = 9,N = 4
為例,計算:9 + 99 + 999 +9,999 = 11,106
個位:
num[0] = 9 * 4 % 10 = A * N % 10 = 6
個位的進位為carry = (9 * 4 ) / 10 = 3
十位:
num[1] = (9 * 3 % 10 + 3) % 10 = (A * (N - 1) % 10 + carry) % 10 = 0
十位的進位為carry = (9 * 3 + 3) / 10 = 3
百位:
num[2] = (9 * 2 % 10 + 3) % 10= (A * (N - 2) % 10 + carry) % 10 = 1
百位的進位為carry = (9 * 2 + 3) / 10 = 2
千位:
num[3] = (9 * 1 % 10 + 2 ) % 10= (A * (N - 3) % 10 + carry) % 10 = 1
千位的進位為carry = (9 * 1 + 2) / 10 = 1
萬位:
num[4] = 1
-
可見滿足規律:
num[i] = (A * (N - i) % 10 + carry) % 10
和carry = (A * (N - i) + carry) / 10
結果必為N位或者N+1位數,其中如果有N+1位數其數值必為1。
conclusion
- 完結了呀
- 熟悉了c的很多基本操作
- 期間因為參加六級考試和做csapp的實驗,斷了一個月的訓練時間,不過還是搞定了
- 是一段艱苦的旅程,但還是很愉快地學到許多技巧
- 最近在聽佐藤直紀的《異邦人の刃》和《空の涯まで》,以及五月天的《有些事現在不做 一輩子都不會做了》,推薦給你們
21.12.21