Function Link: PTA
6-1 简单输出整数 (10 分) 本题要求实现一个函数,对给定的正整数N,打印从1到N的全部正整数。
1 2 3 4 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点的值。
1 2 3 4 5 6 7 8 9 10 double f ( int n, double a[], double x ) { double sum; double x0 = 1 ; for (int i=0 ; i <= n; i++){ if (i == 0 ); else x0 *= x; sum += a[i] * x0; } return sum; }
思路: 一开始的思路用了2个for循环,提交后提示复杂度O(n^2)不行。于是,github里查起答案:x0可以在1个循环里逐个叠加
6-3 简单求和 (10 分) 本题要求实现一个函数,求给定的N个整数的和。
1 2 3 4 5 6 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。
1 2 3 4 5 6 7 ElementType Average ( ElementType S[], int N ) { ElementType sum = 0 ; for (int i = 0 ; i < N; i++){ sum += S[i]; } return sum/(ElementType)N; }
思路: 被除的N要强制转换为ElementType,让结果输出为浮点数
6-5 求自定类型元素的最大值 (10 分) 本题要求实现一个函数,求N个集合元素S[]的平均值,其中集合元素的类型为自定义的ElementType。
1 2 3 4 5 6 7 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
范围内
1 2 3 4 5 6 7 8 9 10 11 int FactorialSum ( List L ) { int sum = 0 ; int num; while (L != NULL ){ 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
等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int IsTheNumber ( const int N ) { int res = N; int num[10 ] = {0 }; if ((int )sqrt (N) == sqrt (N)){ while (res != 0 ){ num[res % 10 ] ++; res /= 10 ; } for (int i = 0 ; i < 10 ; i ++ ){ if (num[i] > 1 ) return 1 ; } } return 0 ; }
思路: 用数组num[10]
分别计数0 ~ 9
,具体要使用取余(%10)
,除法(/10)
来计数 、提取数值
6-8 简单阶乘计算 (10 分) 其中N是用户传入的参数,其值不超过12
。如果N
是非负整数,则该函数必须返回N
的阶乘,否则返回0
。
1 2 3 4 5 6 7 8 9 10 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
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int Count_Digit ( const int N, const int D ) { int n = N; int num[10 ] = {0 }; if (n < 0 ) n = ~n+1 ; if (n == 0x80000000 ){ 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 ) { if (D == 0 ) return 1 ; else return 0 ; } else while (n){ num[n % 10 ]++; n /= 10 ; } return num[D]; }
思路: 分类讨论。1、n == 0x80000000
、n == 0
,注意要使用==
等价符号;2、将负数转为正数处理。
6-10 阶乘计算升级版 (20 分) 本题要求实现一个打印非负整数阶乘的函数。(最大为1000!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void Print_Factorial (const int N) { long sum = 1 ; if (N >= 0 && N <= 12 ) { 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 ) { int Num[3000 ] = { 0 }; int i, j, k, n; k = 1 ; n = 0 ; Num[0 ] = 1 ; int temp; for (i = 2 ; i <= N; i++){ for (j = 0 ; j < k; j++){ temp = Num[j] * i + n; Num[j] = temp % 10 ; n = temp / 10 ; } while (n != 0 ){ Num[k] = n % 10 ; k++; n = n / 10 ; } } 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
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 ]; }
思路: 使用希尔算法,时间复杂度为O(n^(1.3 ~ 2))
。而选择算法、冒泡算法的时间复杂度为O(n^2)
不符合题目时间要求。 参考: Link:希尔算法java实现图示 ;参考答案1 ;参考答案2 。
6-12 判断奇偶性 (10 分) 本题要求实现判断给定整数奇偶性的函数。
1 2 3 4 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在数列中的位置。
1 2 3 4 5 6 7 8 9 10 int Search_Bin (SSTable T, KeyType k) { int start = 0 , end = T.length - 1 , mid; while (start <= end){ mid = (start + end)/2 ; if (T.R[mid].key == k) return mid; else if (T.R[mid].key > k) end = mid - 1 ; else 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
英寸。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #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 ; float foot = m / 0.3048 ; return foot; } int getinch (int cm) { return (c2f(cm) - (int )c2f(cm)) * 12 ; }
思路:**int/int
直接按float
输出,会输出0
**。解决方案:将分子、分母任意一个值改成float
。
7-2 然后是几点 (15 分) 有时候人们用四位数字表示一个时间,比如1106
表示 11
点零6
分。现在,你的程序要根据起始时间和流逝的时间计算出终止时间。
读入两个数字,第一个数字以这样的四位数字表示当前时间,第二个数字表示分钟数,计算当前时间经过那么多分钟后是几点,结果也表示为四位数字。当小时为个位数时,没有前导的零,例如5
点30
分表示为530
;0
点 30
分表示为030
。注意,第二个数字表示的分钟数可能超过60
,也可能是负数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> int main () { int a, b, Mul60, h, min; scanf ("%d %d" , &a, &b); Mul60 = (a / 100 ) * 60 + (a % 100 ) + b; h = Mul60 / 60 ; min = Mul60 % 60 ; printf ("%d%02d" ,h,min); return 0 ; }
思路:因为60
进制转化为60
的倍数,并且分为h
、min
两段输出,注意要使用%02d
。
7-3 逆序的三位数 (10 分) 程序每次读入一个正3
位数,然后输出按位逆序的数字。注意:当输入的数字含有结尾的0
时,输出不应带有前导的0
。比如输入700
,输出应该是7
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> void neg (int num) ;int main () { int num; scanf ("%d" , &num); neg(num); return 0 ; } void neg (int num) { int f = num % 10 ; int s = (num % 100 - f) / 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
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #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); else printf ("%d%d" , s, f); }
思路:用位级运算取个、十位,再单独处理十位为0
的情况(因为最终是并列输出,防止输出两个0
)。位级运算有时确实比数级运算方便。
7-5 表格输出 (5 分) 本题要求编写程序,按照规定格式输出表格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #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的顺序输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> int main () { int i; float f1, f2; char c; scanf ("%f %d %c %f" , &f1, &i, &c, &f2); printf ("%c %d %0.2f %0.2f" , c, i, f1, f2); return 0 ; }
思路:scanf()
不支持带点的格式写法,可以有长度限制,但不可以有小数位数限制。
7-7 12-24小时制 (15 分) 编写一个程序,要求用户输入24小时制的时间,然后显示12小时制的时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 #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); 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”。
1 2 3 4 5 6 7 8 9 #include <stdio.h> int main () { int v; scanf ("%d" , &v); if (v > 60 ) printf ("Speed: %d - speeding" , v); else printf ("Speed: %d - OK" , v); return 0 ; }
思路:题目是超出60
,暗示着不包括60
。
7-9 用天平找小球 (10 分) 三个球A、B、C,大小形状相同且其中有一个球与其他球重量不同。要求找出这个不一样的球。
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main () { int A, B, C; scanf ("%d %d %d" , &A, &B, &C); if (A == B) printf ("%c" , 'C' ); 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元/小时。请按该计酬方式计算员工的工资。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #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 ); } 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。请编写程序实现水费的计算。
1 2 3 4 5 6 7 8 9 #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个整数进行加、减、乘、除或求余运算。题目保证输入和输出均不超过整型范围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #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”(即“有上影线”)。请编程序,根据给定的四个价格组合,判断当日的蜡烛是一根什么样的蜡烛。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #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) 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的所有整数以及这些数的和。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> int main () { int A, B; int i,j; int sum = 0 ; scanf ("%d %d" , &A, &B); if ((B - A) <= 4 ){ 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 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #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" ); 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> int main () { double PI = 1 , up = 1 , down = 1 , last = 1 ; double i; double t; scanf ("%lf" , &t); 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位数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #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 ; for (k = a; k <= a+3 ; k++){ if (i == k || j == k) continue ; 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将调用十八次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #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)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> int main () { int n,u,d; scanf ("%d%d%d" ,&n,&u,&d); int t = 0 ,place = 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <stdio.h> 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); 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); return 0 ; } else if (func_a * func_mid > 0 ) a = mid; else if (func_b * func_mid > 0 ) b = mid; } 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 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int * get () { int *coef; int i; for (i = 0 ; i <= 3 ; i++) scanf ("%d" , &coef[i]); return coef; } int *coef = get();double func (int *coef, double x) { int i; return coef[0 ] *x*x*x + coef[1 ] *x*x +coef[2 ] *x +coef[3 ]; }
thoughts:
try to submit array address to func, but segmentation fault
.
try to use double pow(double x , double n)
, but also segmentation 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分,问该支票面额是多少?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> int main () { int y, f, n; int i = 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 2 3 4 5 6 7 8 9 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
的部分口诀表。
1 2 3 4 5 6 7 8 9 10 11 12 13 #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 ,求方程X ^2+Y ^2=N 的全部正整数解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> int main () { int i, j, n, flag = 0 , a[10 ], b[10 ]; scanf ("%d" , &n); 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++; } } if (!flag) printf ("No Solution" ); else for (i = flag - 1 ; i >= 0 ; i--) printf ("%d %d\n" , a[i], b[i]); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #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分钟后乌龟和兔子谁跑得快?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #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 ; scanf ("%d" , &T); while (T--){ turtle += tur_speed; if (rab_time-- > 0 ) rabbit += rab_speed; if (rab_time == 0 ){ if (rabbit > turtle && rab_sleep != 0 ) rab_sleep = 30 ; else rab_time = 10 ; } if (rab_sleep-- == 0 ) 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”元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #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 ){ printf ("a" ); } while (num != 0 ){ i = num % 10 ; data[count] = i; count++; num = num / 10 ; } dec = count + 1 ; for (j = count-1 ; j >= 0 ; j--){ dec--; if (temp > 10000 && data[j] == 0 && data[j-1 ] == 0 && data[1 ] != 0 && flag == 0 ){ flag++; printf ("W" ); } if (data[j] == 0 && data[j-1 ] == 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的分数形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 #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; for (x = 1 ; x <= x_max; x++) if (num % x == 0 && den % x == 0 ) com_fac_max = x; 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).
还找到了一个简洁优雅的递归函数来求最大公因数:
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int gcd (int x, int y) {return y ? gcd(y, x%y) : x;}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
字。十个数字对应的拼音如下:
1 2 3 4 5 6 7 8 9 10 0: ling 1: yi 2: er 3: san 4: si 5: wu 6: liu 7: qi 8: ba 9: jiu
**AC code: **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #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 ; } if (num == -2147483648 ){ printf ("fu er yi si qi si ba san liu si ba" ); return 0 ; } for (i = 1 ; num != 0 ;i++){ cut[i] = num % 10 ; num /= 10 ; } 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。注意,行中可能出现连续的空格;最后的.
不计算在内。
**AC code: **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> int main () { char c; int flag = 0 , count; while (1 ){ count = 0 ; scanf ("%c" ,&c); while (c != ' ' && c != '.' ){ count++; scanf ("%c" , &c); } if (count != 0 ){ flag++; if (flag == 1 ) printf ("%d" , count); else printf (" %d" , count); } if (c == '.' ) break ; } return 0 ; }
ideas:
Before counting, we must set(reset) count
and the first c
.
The format of output are one numbers: %d
or some numbers: %d %d %d %d
, so we must set flag
.
7-27 冒泡法排序 (20 分) 将N 个整数按从小到大排序的冒泡排序法是这样工作的:从头到尾比较相邻两个元素,如果前面的元素大于其紧随的后面元素,则交换它们。通过一遍扫描,则最后一个元素必定是最大的元素。然后用同样的方法对前N −1个元素进行第二遍扫描。依此类推,最后只需处理两个元素,就完成了对N 个数的排序。
本题要求对任意给定的K (<N ),输出扫描完第K 遍后的中间结果数列。
输入格式:
输入在第1行中给出N 和K (1≤K <N ≤100),在第2行中给出N 个待排序的整数,数字间以空格分隔。
输出格式:
在一行中输出冒泡排序法扫描完第K 遍后的中间结果数列,数字间以空格分隔,但末尾不得有多余空格。
输入样例:
输出样例:
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #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]){ temp = num[j]; num[j] = num[j - 1 ]; num[j - 1 ] = temp; } } N--; } for (i = 0 ; i < N+K; i++){ 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #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 ; elimination++; if (elimination == 3 ){ a[i] = 0 ; elimination = 0 ; remainder--; } } } 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> #include <string.h> int main () { char s1[100 ], s2[100 ], temp[100 ]; gets(s1); gets(s2); char *s1_s2; while (s1_s2 = strstr (s1, s2)){ strcpy (temp, s1_s2 + strlen (s2)); *s1_s2 = '\0' ; strcat (s1, temp); } 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> #include <string.h> int main () { int N, K; int i, j; scanf ("%d %d" , &N, &K); char str[N][11 ]; char temp[11 ]; 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 ){ strcpy (temp, str[j]); strcpy (str[j], str[j+1 ]); strcpy (str[j+1 ], temp); } } 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,则返回正数。
字符串函数参考链接 ;c语言NULL和0区别及NULL详解
7-31 字符串循环左移 (20 分) 输入一个字符串和一个非负整数N ,要求将字符串循环左移N 次。
输入格式:
输入在第1行中给出一个不超过100个字符长度的、以回车结束的非空字符串;第2行给出非负整数N 。
输出格式:
在一行中输出循环左移N 次后的字符串。
输入样例:
输出样例:
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #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 ){ puts (s1); return 0 ; } if (n > len){ 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); 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个空格。
输入样例:
1 2 Hello World Here I Come 结尾无空行
输出样例:
1 2 Come I Here World Hello 结尾无空行
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <stdio.h> #define MAX 500000 int main () { char c; char t[MAX]; int i = 0 , count = 0 , flag = 0 ; while ((c = getchar()) != '\n' ) { if (c != ' ' ) { flag = 1 ; t[i++] = c; count = 0 ; } else if (count > 0 ) { continue ; } else if (flag) { t[i++] = c; count = 1 ; } } count = 0 ; int j; for (i -= 1 ; i >= 0 ; i--) { if (t[i] != ' ' ) { count ++; } else if (t[i] == ' ' && count > 0 ) { for (j = i+1 ; j <= i+count; j++) { printf ("%c" , t[j]); } printf (" " ); count = 0 ; } } 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:
输入样例2:
输出样例2:
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> int gcd (int x, int y) {return y ? gcd(y, x%y) : x;}int main () { int a1,a2,b1,b2; int a,b; scanf ("%d/%d %d/%d" , &a1, &b1, &a2, &b2); if (b1 == b2){ a = a1 + a2; b = b1; } else { b = b1 * b2; a1 = a1 * b2; a2 = a2 * b1; a = a1 + a2; } if (a%b == 0 ) printf ("%d" , a/b); else { 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 分))
7-34 通讯录的录入与显示 (10 分) 日期:21.11.8
通讯录中的一条记录包含下述基本信息:朋友的姓名、出生日期、性别、固定电话号码、移动电话号码。 本题要求编写程序,录入N 条记录,并且根据要求显示任意某条记录。
输入格式:
输入在第一行给出正整数N (≤10);随后N 行,每行按照格式姓名 生日 性别 固话 手机
给出一条记录。其中姓名
是不超过10个字符、不包含空格的非空字符串;生日按yyyy/mm/dd
的格式给出年月日;性别用M
表示“男”、F
表示“女”;固话
和手机
均为不超过15位的连续数字,前面有可能出现+
。
在通讯录记录输入完成后,最后一行给出正整数K ,并且随后给出K 个整数,表示要查询的记录编号(从0到N −1顺序编号)。数字间以空格分隔。
输出格式:
对每一条要查询的记录编号,在一行中按照姓名 固话 手机 性别 生日
的格式输出该记录。若要查询的记录不存在,则输出Not Found
。
输入样例:
1 2 3 4 5 6 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 结尾无空行
输出样例:
1 2 3 LaoLao 057187951100 +8618618623333 F 1967/11/30 Not Found 结尾无空行
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> struct unit { char name[11 ]; char day[11 ]; char gender; char telephone[17 ]; 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); for (i = 0 ; i < K; i++){ scanf ("%d" , &num); if (num >=0 && num < N) 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:
1 2 3 4 1/2 1/6 3/6 -5/10 结尾无空行
输出样例1:
输入样例2:
输出样例2:
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <stdio.h> int gcd (int x, int y) {return y ? gcd(y, x%y) : x;}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++){ 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:
输出样例1:
1 2 3 4 5 (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:
输出样例2:
1 2 3 4 (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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #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的所有整数分解式子。递增顺序是指:对于两个分解序列N 1={n 1,n 2,⋯}和N 2={m 1,m 2,⋯},若存在i 使得n 1=m 1,⋯,n i=m i,但是 ni*+1<*m i*+1,则N 1序列必定在N 2序列之前输出。每个式子由小到大相加,式子间用分号隔开,且每输出4个式子后换行。
输入样例:
输出样例:
1 2 3 4 5 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <stdio.h> int N;int num[31 ]; int index = -1 ; int sum = 0 ; int count = 0 ; void division (int x) ;int main () { scanf ("%d" , &N); division(1 ); 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++) { num[++index] = i; sum += i; division (i); sum -= i; index --; } }
思路: 如图所示,以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 的值。
输入样例:
输出样例:
AC code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h> #include <stdlib.h> int main () { int A = 0 ; int N = 0 ; scanf ("%d%d" , &A, &N); int flag = 0 ; int carry = 0 ; int * num = (int *)malloc (sizeof (int ) * (N + 1 )); if (A == 0 || N == 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 ){ 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