C语言程序设计精髓 哈工大Mooc第八章 编程题
练兵区
1三天打渔两天晒网(4分)
题目内容:
中国有句俗语叫“三天打鱼两天晒网”,某人从1990年1月1日起开始“三天打鱼两天晒网”,即工作三天,然后再休息两天。问这个人在以后的某一天中是在工作还是在休息。从键盘任意输入一天,编程判断他是在工作还是在休息,如果是在工作,则输出:He is working,如果是在休息,则输出:He is having a rest,如果输入的年份小于1990或者输入的月份和日期不合法,则输出:Invalid input。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
// 不合法返回-1,休息返回0,工作返回1
int workOrRest(int year, int month, int day);
// 校验日期合法性
int isValid(int year, int month, int day);
// 判断是否是闰年
int isLeap(int year);
int main(){
int year, month, day;
scanf("%4d-%2d-%2d",&year, &month, &day);
int res = workOrRest(year, month, day);
switch(res){
case 1:
printf("He is working");
break;
case 0:
printf("He is having a rest");
break;
default:
printf("Invalid input");
}
return 0;
}
int workOrRest(int year, int month, int day){
// 非法返回-1
if(!isValid(year, month, day)) return -1;
int sum = 0;
for(int i = year - 1990; i > 0; i--){
sum += isLeap(year - i) ? 366 : 365;
}
int dayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(isLeap(year)) dayOfMonth[1] = 29;
for(int i = month-1; i > 0; i--){
sum += dayOfMonth[i - 1];
}
sum += day;
int symbol = sum % 5;
if(symbol >0&&symbol <= 3) return 1;
else return 0;
}
int isValid(int year, int month, int day){
int dayOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(year < 1990) return 0;
if(month <= 0 || month > 12) return 0;
if(isLeap(year)) dayOfMonth[1] = 29;
if(day <= 0 || dayOfMonth[month - 1] < day) return 0;
return 1;
}
int isLeap(int year){
if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return 1;
else return 0;
}
2统计用户输入(4分)
题目内容:
从键盘读取用户输入直到遇到#字符,编写程序统计读取的空格数目、读取的换行符数目以及读取的所有其他字符数目。(要求用getchar()输入字符)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int main(){
int a[3];
memset(a, 0, sizeof(a));
while(1){
char ch = getchar();
if(ch == '#'){
break;
}
if(ch == ' '){
a[0]++;
}
else if(ch == '\n'){
a[1]++;
}
else{
a[2]++;
}
}
printf("Please input a string end by #:\n");
printf("space: %d,newline: %d,others: %d\n", a[0], a[1], a[2]);
return 0;
}
3统计正整数中指定数字的个数(4分)
题目内容:
从键盘输入一个正整数number,求其中含有指定数字digit的个数。例如:从键盘输入正整数number=1222,若digit=2,则1223中含有 3个2,要求用函数实现。函数原型为:int CountDigit(int number,int digit);
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int CountDigit(int number,int digit);
int main(){
int digit,number;
printf("Input m,n:\n");
scanf("%d,%d", &number, &digit);
int res = CountDigit(number, digit);
printf("%d\n", res);
return 0;
}
int CountDigit(int number,int digit){
int a[10], temp;
memset(a, 0, sizeof(a));
while(number>0){
temp = number % 10;
number /= 10;
a[temp]++;
}
return a[digit];
}
4玫瑰花数(4分)
题目内容:
如果一个n位正整数等于它的n个数字的n次方和,则称该数为n位自方幂数。四位自方幂数称为玫瑰花数。编程计算并输出所有的玫瑰花数。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int main(){
int thousand, hundred, ten, one, sum;
for(int i = 1000;i<10000;i++){
thousand = i / 1000;
hundred = i / 100 - thousand * 10;
ten = i / 10 % 10;
one = i % 10;
sum = pow(thousand, 4) + pow(hundred, 4) + pow(ten, 4) + pow(one, 4);
if(sum == i){
printf("%d\n", sum);
}
}
return 0;
}
5四位反序数(4分)
题目内容:
反序数就是将整数的数字倒过来形成的整数。例如,1234的反序数是4321。设N是一个四位数,它的9倍恰好是其反序数,编程计算并输出N的值。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int isReverse(int number);
int getNumAtNPos(int number,int n, int length);
int getLength(int number);
int main(){
int thousand, hundred, ten, one, sum;
for(int i = 1;i < 1000000;i++){
// 改为i = 1000; i< 10000就是题解
if(isReverse(i)){
printf("%d\n", i);
}
}
return 0;
}
int isReverse(int number) {
int length = getLength(number);
int left, right, reverseNum = number*9;
if(getLength(reverseNum) != length) return 0;
// printf("reverseNum:%d ", reverseNum);
int start = 1;
while(length > 0){
// printf("%d", getNumAtNPos(number, start, getLength(number)));
// printf("%d\n", getNumAtNPos(reverseNum % (int)pow(10, start), 1, start));
int flag = getNumAtNPos(number, start, getLength(number)) == getNumAtNPos(reverseNum % (int)pow(10, start), 1, start);
if(!flag) return 0;
start++;
length--;
}
return 1;
}
int getNumAtNPos(int number,int n, int length){
return number / (int)pow(10,(length-n)) % 10;
}
int getLength(int number){
int count = 0;
while(number > 0){
count++;
number /= 10;
}
return count;
}
我这道题求的是在1-n上得解,如果嫌麻烦可以直接看这篇:题解
我解释一下我的代码:
- isReverse判断是否是反序数字
- getNumAtNPos得到在第n位上的数字
- getLength返回一个数字的长度
- 对于一个长为length的正整数x有:
- 从左到右的第n位数可以表示为:
x / 10^(length - n) % 10
- 从右到左的第n位数可以表示为:
getNumAtNPos(x % 10^n, 1, n)
至于解,我不知道全不全,反正求出来的演算都没有问题
- 从左到右的第n位数可以表示为:
- 如果只是解1000-9999之间的一个解,大可以确定解在1000-1111之间,然后用数组来存储
number
和·numebr * 9
的四个不同位,然后遍历即可。 - 推广一下就可以求1-n的解了,当
number
与number * 9
长度不一致时,显然不可能是解;当长度一致时,声明一个长度为number
的数组,存储从左到右number
的每一位,然后从右到左依次取number * 9
的每一位与对应的下标的数组元素对比即可。
68除不尽的自然数(4分)
题目内容:
一个自然数被8除余1,所得的商被8除也余1,再将第二次的商被8除后余7,最后得到一个商为a。又知这个自然数被17除余4,所得的商被17除余15,最后得到一个商是a的2倍。求满足以上条件的最小自然数。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int isTarget(int number);
int main(){
for(int index = 0; ;index++){
if(isTarget(index)){
printf("%d\n", index);
break;
}
}
return 0;
}
int isTarget(int number){
int a;
if(number % 8 == 1){
if(number / 8 % 8 == 1){
if(number / (8*8) % 8 == 7){
a = number/(8*8*8);
}else return 0;
}else return 0;
}else return 0;
if(number % 17 == 4){
if(number / 17 % 17 == 15){
if(2*a == number / (17*17)){
return 1;
}else return 0;
} else return 0;
}else return 0;
}
7矩阵转置v1.0(4分)
题目内容:
用二维数组作为函数参数,编程计算并输出n×n阶矩阵的转置矩阵。其中,n的值不超过10,n的值由用户从键盘输入。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
/*
* 二维数组作为参数必须传递第二维度大小
* 因为c语言中数组按行存储,不给出第二纬度大小
* 就无法确定一个元素相对于第一个元素的偏移位置
*/
void readElement(int arr[][10], int n);
void matrixTranspose(int arr[][10], int n);
int main() {
int n;
printf("Input n:");
scanf("%d", &n);
int arr[10][10];
printf("Input %d*%d matrix:\n",n,n);
readElement(arr, n);
matrixTranspose(arr, n);
printf("The transposed matrix is:\n");
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
printf("%4d", arr[i][j]);
}
printf("\n");
}
return 0;
}
void readElement(int arr[][10], int n) {
int input;
for(int i = 0; i <= n-1; i++) {
for(int j = 0; j <= n-1; j++) {
scanf("%d", &input);
arr[i][j] = input;
if(getchar() == '\n') {
break;
}
}
}
}
void matrixTranspose(int arr[][10], int n) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < i; j++) {
int temp;
temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
- 读入矩阵后,我们只需要遍历一个上三角矩阵 / 下三角矩阵就行了。
比如:1 2 3 4 1 5 6 7 8 => 5 6 6 6 6 6 => 6 6 6 7 8 9 1 7 8 9 1
- 对于坐标为
a[i][j
的元素,它转置后对应的位置在:a[j][i]
- 对于对角线上的元素可以不用转置
8兔子生崽问题(4分)
题目内容:
假设一对小兔的成熟期是一个月,即一个月可长成成兔,那么如果每对成兔每个月都可以生一对小兔,一对新生的小兔从第二个月起就开始生兔子,试问从一对兔子开始繁殖,n(n<=12)月以后可有多少对兔子(即当年第n月份总计有多少对兔子,含成兔和小兔)?请编程求解该问题,n的值要求从键盘输入。
- 尾递归
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int rabitReproduction(int childrenNum,int matureNum, int month);
int main() {
int n;
printf("Input n(n<=12):\n");
scanf("%d", &n);
int res = rabitReproduction(0, 1, n);
printf("\nTotal=%d\n", res);
return 0;
}
int rabitReproduction(int childrenNum,int matureNum, int month){
if(month == 0) return matureNum;
printf("%4d", childrenNum + matureNum);
return rabitReproduction(matureNum, childrenNum + matureNum, month-1);
}
- 递归
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int rabitReproduction(int childrenNum,int matureNum, int month);
int main() {
int n;
printf("Input n(n<=12):\n");
scanf("%d", &n);
int res = rabitReproduction(0, 1, n);
printf("\nTotal=%d\n", res);
return 0;
}
int rabitReproduction(int childrenNum,int matureNum, int month){
printf("%4d", childrenNum + matureNum);
if(month == 1) return 1;
return matureNum + rabitReproduction(matureNum, childrenNum + matureNum, month-1);
}
递归解可能有点难理解,我解释一下:其实就是每个月新生的兔子数量相加,但是这样还少了初始的那对兔子,所以最后 + 1就行了。
9抓交通肇事犯(4分)
题目内容:
一辆卡车违犯交通规则,撞人后逃跑。现场有三人目击事件,但都没记住车号,只记下车号的一些特征。甲说:牌照的前两位数字是相同的;乙说:牌照的后两位数字是相同的,但与前两位不同;丙是位数学家,他说:四位的车号刚好是一个整数的平方。现在请根据以上线索帮助警方找出车号以便尽快破案。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
int isTarget(int sum);
int main() {
int res;
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
res = isTarget(1000*i + 100*i + 10*j + j);
if(res > 0){
printf("k=%d,m=%d\n", 1000*i + 100*i + 10*j + j, res);
return 0;
}
}
}
return 0;
}
int isTarget(int sum){
for(int start = 31; start < 100;start++){
if(sum == start * start){
return start;
}
}
return -1;
}
10检验并打印幻方矩阵(4分)
题目内容:
幻方矩阵是指该矩阵中每一行、每一列、每一对角线上的元素之和都是相等的。从键盘输入一个5×5的矩阵并将其存入一个二维整型数组中,检验其是否为幻方矩阵,并将其按指定格式显示到屏幕上。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
#define N 5
void readElement(int arr[][N], int n);
void getRowSum(int arr[][N], int res[], int n);
void getColumnSum(int arr[][N], int res[], int n);
void getDiagonalSum(int arr[][N], int res[], int n);
int main() {
int arr[N][N];
readElement(arr, N);
int rowSum[N] = {0};
getRowSum(arr, rowSum, N);
int columnSum[N] = {0};
getColumnSum(arr, columnSum, N);
int diagonalSum[2] = {0};
getDiagonalSum(arr, diagonalSum, N);
int sum = rowSum[0];
int flag = 1;
for(int i = 0;i < N; i++){
if(sum != rowSum[i] || sum != columnSum[i]){
flag = 0;
break;
}
if(i < 2&&diagonalSum[i] != sum){
flag = 0;
break;
}
}
if(flag){
printf("It is a magic square!\n");
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
printf("%4d", arr[i][j]);
}
printf("\n");
}
}else printf( "It is not a magic square!\n");
return 0;
}
void readElement(int arr[][N], int n) {
int input;
for(int i = 0; i <= n-1; i++) {
for(int j = 0; j <= n-1; j++) {
scanf("%d", &input);
arr[i][j] = input;
if(getchar() == '\n') {
break;
}
}
}
}
void getRowSum(int arr[][N], int res[], int n){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
res[i] += arr[i][j];
}
}
}
void getColumnSum(int arr[][N], int res[], int n){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
res[i] += arr[j][i];
}
}
}
void getDiagonalSum(int arr[][N], int res[], int n){
for(int i = 0; i<N; i++){
res[0] += arr[i][i];
res[1] += arr[N-1-i][i];
}
}
第8周编程题在线测试
1摘苹果(4分)
题目内容:
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个30厘米高的板凳,当他不能直接用手摘到苹果的时候,就会踩到板凳上再试试。现在已知10个苹果到地面的高度(已知在100cm到200cm之间,包括100cm和200cm),以及陶陶把手伸直时能达到的最大高度(已知在100cm到120cm之间,包括100cm和120cm),请你编写程序帮助陶陶计算一下他能摘到的苹果数目。假设他碰到苹果,苹果就会掉下来。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
#define N 10
int GetApple(int a[], int height, int n);
void inputHeight(int a[]);
int main(){
int a[N], taoHeight;
inputHeight(a);
scanf("%d", &taoHeight);
taoHeight += 30;
int count = 0;
for(int i = 0; i < N; i++){
if(a[i] <= taoHeight) count++;
}
printf("%d", count);
return 0;
}
void inputHeight(int a[]){
int input;
for(int i = 0; i < N; i++){
scanf(" %d", &input);
a[i] = input;
}
}
2好数对(4分)
题目内容:
已知一个集合A,对A中任意两个不同的元素求和,若求得的和仍在A内,则称其为好数对。例如,集合A={1 2 3 4},1+2=3,1+3=4,则1,2和1,3 是两个好数对。编写程序求给定集合中好数对的个数。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
#define N 1000
int getTotal(int a[], int arrSize);
void inputAssembly(int a[], int arrSize);
int isTarget(int a[], int sum, int size);
int main(){
int size, arr[N];
scanf("%d", &size);
inputAssembly(arr, size);
int res = getTotal(arr, size);
printf("%d", res);
return 0;
}
void inputAssembly(int a[], int arrSize){
int input;
for(int i = 0; i < arrSize; i++){
scanf("%d", &input);
a[i] = input;
}
}
int getTotal(int a[], int arrSize){
int count = 0;
for(int i = 0; i < arrSize; i++){
for(int j = i+1; j < arrSize; j++){
if(isTarget(a, a[i] + a[j], arrSize)){
count++;
}
}
}
return count;
}
int isTarget(int a[], int sum, int size){
for(int i = 0; i < size; i++){
if(a[i] == sum) return 1;
}
return 0;
}
3组合三位数(4分)
题目内容:
将0到9这十个数字分成三个3位数,要求第一个3位数,正好是第二个3位数的1/2,是第三个3位数的1/3。问应当怎样分,编写程序实现。
#include <stdio.h>
#include<stdbool.h>
int main()
{
int p[10],num[3];
for(int i=100;i<=333;i++)
{
for(int j=0;j<10;j++)
{
p[j]=0;
}
for(int m=0;m<3;m++)
{
num[m]=i*(m+1);
int mid=num[m];
while(mid!=0)
{
p[mid%10]++;
mid/=10;
}
}
bool flag=true;
for(int k=0;k<10;k++)
{
if(p[k]>1)
{
flag=false;break;
}
}
if(flag==true)
{
printf("%d,%d,%d\n" ,num[0],num[1],num[2]);
}
}
return 0;
}
4求100以内的最大素数(4分)
题目内容:
编程计算n(n<=500)以内的10个最大素数及其和,分别输出这最大的10个素数及其和。n的值要求从键盘输入。要求10个素数按从大到小的顺序输出。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <malloc.h>
#include <time.h>
#include<string.h>
#define N 10
int isPrime(int n);
int main(){
int input,count = 10, res[N], sum = 0;
memset(res, 0, sizeof(res));
printf("Input n(n<=500):");
scanf("%d", &input);
for(; input > 1; input--){
if(count == 0) break;
if(!isPrime(input)){
res[--count] = input;
sum += res[count];
}
}
for(int i = N - count,j = N - 1; i > 0; i--,j--){
printf("%6d", res[j]);
}
printf("\nsum=%d\n", sum);
return 0;
}
int isPrime(int n){
for(int i = 2; i <= sqrt(n); i++){
if(n % i == 0) return 1;
}
return 0;
}