《算法笔记》学习日记——5.1 简单数学

5.1 简单数学

Codeup Contest ID:100000588

问题 A: 守形数

题目描述
守形数是这样一种整数,它的平方的低位部分等于它本身。
比如25的平方是625,低位部分是25,因此25是一个守形数。
编一个程序,判断N是否为守形数。
输入
输入包括1个整数N,2<=N<100。
输出
可能有多组测试数据,对于每组数据,
输出"Yes!”表示N是守形数。
输出"No!”表示N不是守形数。
样例输入

6
11

样例输出

Yes!
No!

思路
思路就是把输入的数进行平方操作之后,利用sprintf把所得的数暂存在一个char数组中作为一个字符串,然后从字符串的中间位置(strlen(str)-原来数的位数)开始遍历一直到末尾,再把这一段的字符串截取出来放在一个新的char数组中,用sscanf转化成整数看跟原数是否相等,如果相等,则是守形数,否则,不是。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
char str1[3]={0};//存储原数 
char str2[5]={0};//存储平方后的数 
char temp[5]={0};//用于存放截取后的字符串 
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		sprintf(str1, "%d", n);
		int len = strlen(str1);//计算原数的位数 
		int strr = pow(n,2);
		sprintf(str2, "%d", strr);
		int index = 0;
		for(int i=strlen(str2)-len;i<strlen(str2);i++){
			temp[index] = str2[i];
			index++;
		}
		int tmp;//将截出来的字符串转换成整数 
		sscanf(temp, "%d", &tmp); 
		if(tmp==n) printf("Yes!\n");
		else printf("No!\n");
		memset(str1, 0, sizeof(str1));
		memset(str2, 0, sizeof(str2));
		memset(temp, 0, sizeof(temp));
	}
	return 0;
} 

问题 B: 反序数

题目描述
设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321)
求N的值
输入
程序无任何输入数据。
输出
输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。
思路
首先,要解决的问题是如何将一个四位数反序,我认为这类问题的话,肯定是把整数转换成字符串来操作要方便,比如我要判断1234,那就把1234转换成字符串,然后从末尾开始遍历,将每一位放在一个新的字符数组中,最后将新的字符数组转换成整数,这样就得到了一个反序数。
然后,再根据约束条件,如果反序数恰好等于原数的9倍,那就输出,否则,就不输出。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int MyReverse(int a){
	char str1[5]={0};
	char str2[5]={0};
	sprintf(str1, "%d", a);//把a转化成字符串str1
	for(int i=strlen(str1)-1, j=0;i>=0, j<strlen(str1);i--, j++) str2[j] = str1[i];//从末尾遍历,依次将字符赋给新字符串str2
	int b;
	sscanf(str2, "%d", &b);//把反序后的字符串str2转化成整数b
	return b; 
}
int main(){
	int cnt = 0;
	for(int i=1000;i<10000;i++){
		if(i*9==MyReverse(i)){
			cnt++;
			if(cnt==1) printf("%d", i);
			else printf(" %d", i);
		}
	}
	return 0;
} 

问题 C: 百鸡问题

题目描述
用小于等于n元去买100只鸡,大鸡5元/只,小鸡3元/只,还有1/3元每只的一种小鸡,分别记为x只,y只,z只。编程求解x,y,z所有可能解。
输入
测试数据有多组,输入n。
输出
对于每组输入,请输出x,y,z所有可行解,按照x,y,z依次增大的顺序输出。
样例输入

45

样例输出

x=0,y=0,z=100
x=0,y=1,z=99
x=0,y=2,z=98
x=0,y=3,z=97
x=0,y=4,z=96
x=1,y=0,z=99
x=1,y=1,z=98
x=1,y=2,z=97
x=2,y=0,z=98

思路
这题之前学Python的时候用Python来实现过了(百钱白鸡问题),只不过这里是n元,不是100元,思路还是一样的,按照题目要求添加约束条件就行了,要注意的是C/C++中int型的除法是整除,而Python中int型的除法是一定精确的(比如1/2=0.5),所以这题最好都设成double型。
需要注意的是,如果想表达1/3=0.333的话,在C语言里要写成1.0/3(浮点型除以整型,结果会转化成浮点型)。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int main(){
	double n;
	while(scanf("%lf", &n) != EOF){
		double x, y, z;
		for(x=0;x<=n/5;x++){
			for(y=0;y<=n/3;y++){
				for(z=0;z<=n*3;z++){
					//如果正好是一百只鸡,且花费小于n
					if(x+y+z==100&&x*5+y*3+1.0/3*z<=n) printf("x=%.0f,y=%.0f,z=%.0f\n", x, y, z);
				}
			}
		}
	}
	return 0;
} 

问题 D: abc

题目描述
设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。
输入
题目没有任何输入。
输出
请输出所有满足题目条件的a、b、c的值。
a、b、c之间用空格隔开。
每个输出占一行。
思路
由题意可知,abc、bcc是两个三位数,而且相加要等于532,那么思路肯定还是遍历所有三位数,然后把abc转化成bcc,再观察两者相加是否等于532,如果是,就输出a、b、c的值,如果不是,就继续遍历。
那么怎么把abc转化成bcc呢,当然还是用字符串操作啦,看代码吧!
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int TransForm(int a){
	char str1[4]={0};
	char str2[4]={0};
	sprintf(str1, "%d", a);//把a转化成字符串str1 
	str2[0] = str1[1];//b
	str2[1] = str1[2];//c
	str2[2] = str1[2];//c
	int b;
	sscanf(str2, "%d", &b);//把字符串str2转化成整数b
	return b; 
}
int main(){
	for(int i=100;i<1000;i++){
		if(i+TransForm(i)==532){
			char tmp[4]={0};
			sprintf(tmp, "%d", i);
			printf("%c %c %c\n", tmp[0], tmp[1], tmp[2]);
		}
	}
	return 0;
} 

问题 E: 众数

题目描述
输入20个数,每个数都在1-10之间,求1-10中的众数(众数就是出现次数最多的数,如果存在一样多次数的众数,则输出权值较小的那一个)。
输入
测试数据有多组,每组输入20个1-10之间的数。
输出
对于每组输入,请输出1-10中的众数。
注意如果存在一样多次数的众数,则输出权值较小的那一个。
样例输入

8 9 6 4 6 3 10 4 7 4 2 9 1 6 5 6 2 2 3 8

样例输出

6

思路
这题很明显建立一个散列表来做就很简单了,下标对应数,内容对应出现的次数。然后遍历散列表,把出现次数最多的下标输出,这里不用考虑次数一样多取权值较小的问题,因为下标本来就是从小到大有序,我们从头开始遍历找最大值,就不存在这个问题了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int tmp[21]={0};
int hashtable[11]={0};
int main(){
	while(scanf("%d", &tmp[1]) != EOF){
		hashtable[tmp[1]]++;
		for(int i=2;i<=20;i++){
			scanf("%d", &tmp[i]);
			hashtable[tmp[i]]++;
		}
		int max = -1, maxi = -1;
		for(int i=1;i<=10;i++){
			if(hashtable[i]>max){
				max = hashtable[i];
				maxi = i;
			}
		}
		printf("%d\n", maxi);//散列表的下标就是原来的数
		memset(tmp, 0, sizeof(tmp));
		memset(hashtable, 0, sizeof(hashtable));
	}
	return 0;
} 

问题 F: 计算两个矩阵的乘积

题目描述
计算两个矩阵的乘积,第一个是23矩阵,第二个是32矩阵,结果为一个22矩阵。
输入
输入包含多组数据,先输入一个2
3矩阵,再输入一个3*2矩阵。
输出
输出两个矩阵的乘积。
样例输入

1 1 1
1 1 1
1 1
1 1
1 1

样例输出

3 3
3 3

思路
这题只要知道矩阵乘积怎么算就能做出来,这是线性代数的内容,应该是矩阵每一行的元素乘另一个矩阵每一列元素。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int matrix1[2][3];
int matrix2[3][2];
int result[2][2]; 
int main(){
	while(scanf("%d", &matrix1[0][0]) != EOF){
		for(int i=1;i<3;i++) scanf("%d", &matrix1[0][i]);
		for(int i=0;i<3;i++) scanf("%d", &matrix1[1][i]);
		for(int i=0;i<3;i++){
			for(int j=0;j<2;j++) scanf("%d", &matrix2[i][j]);
		}
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++){
				for(int k=0;k<3;k++){
					result[i][j] += matrix1[i][k]*matrix2[k][j];
					//乘积C的第i行第j列的元素等于矩阵A的第i行的元素与矩阵B的第j列对应元素乘积之和	
				}
			}
		}
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++){
				if(j==0) printf("%d", result[i][j]);
				else printf(" %d", result[i][j]);
			}
			printf("\n");
		}
		for(int i=0;i<2;i++) memset(matrix1, 0, sizeof(matrix1));
		for(int i=0;i<3;i++) memset(matrix2, 0, sizeof(matrix2));
		for(int i=0;i<2;i++) memset(result, 0, sizeof(result));
	}
	return 0;
} 

问题 G: 加法等式

题目描述
设a、b、c 均是0 到9 之间的数字,abc、bcc 是两个三位数,且有:abc+bcc=532。求
满足条件的所有a、b、c 的值。
输入
无。
输出
每行输出3个数,分别表示abc的值,用一个空格隔开。
样例输入

样例输出

思路
这题和问题D:abc一模一样,这里就不多说了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int TransForm(int a){
	char str1[4]={0};
	char str2[4]={0};
	sprintf(str1, "%d", a);
	str2[0] = str1[1];
	str2[1] = str1[2];
	str2[2] = str1[2];
	int b;
	sscanf(str2, "%d", &b);
	return b;
}
int main(){
	for(int i=100;i<1000;i++){
		if(i+TransForm(i)==532){
			char tmp[4]={0};
			sprintf(tmp, "%d", i);
			printf("%c %c %c\n", tmp[0], tmp[1], tmp[2]);
		}
	}
	return 0;
} 

问题 H: 整数和

题目描述
编写程序,读入一个整数N。若N为非负数,则计算N 到2N 之间的整数和;若N为一个负数,则求2N 到N 之间的整数和。
输入
第一行表示样例数m,接下来m行每行一个整数N,N的绝对值不超过100。
输出
输出m行,每行表示对应的题目所求。
样例输入

2
2
-1

样例输出

9
-3

提示
注意N可能为负数
思路
这题也是直接按着题目来操作就行了,注意要把非负数和负数的计算方法区分开来就行。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int Sum(int a){
	if(a>=0){
		int sum = 0;
		for(int i=a;i<=2*a;i++) sum += i;
		return sum;
	}
	else{
		int sum = 0;
		for(int i=2*a;i<=a;i++) sum += i;
		return sum;
	}
}
int main(){
	int m;
	while(scanf("%d", &m) != EOF){
		while(m--){
			int tmp;
			scanf("%d", &tmp);
			printf("%d\n", Sum(tmp));
		}
	}
	return 0;
} 

问题 I: 反序相等

题目描述
设N是一个四位数,它的9倍恰好是其反序数(例如:1234 的反序数是4321),求N的值。
输入

输出
每行一个数,表示满足题目要求的数。
思路
这题和问题B:反序数也一模一样,这里不多说了(不知道这题为啥是正确0,看了记录在17年也有正确100的)。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int Reverse(int a){
	char str1[5]={0};
	char str2[5]={0};
	sprintf(str1, "%d", a);
	int index = 0;
	for(int i=strlen(str1)-1;i>=0;i--) str2[index++] = str1[i];
	int b;
	sscanf(str2, "%d", &b);
	return b;
}
int main(){
	for(int i=1000;i<10000;i++){
		if(i*9==Reverse(i)) printf("%d\n", i);
	}
	return 0;
} 

问题 J: 多项式的值

题目描述
实现一个多项式的类(a+bx+cx2+d*x3+…+),要求输入该多项式的系数和x
的值后打印出这个多项式的值。
输入
输入第一行为样例数m,对于每个样例,第一行为多项式最高项次数n,接下来n+1个整数表示每项系数,最后一个整数x,n不超过10。
输出
输出m行,表示个多项式代入x后的值。
样例输入

1
2
1 2 3
2

样例输出

17

思路
首先要读懂这题的题意,按题目意思来说,是不存在非零项的,比如样例给出的最高项指数是2,并给出系数1、2、3,那么多项式就是1*x0+2*x1+3*x2,然后最后把2代入进去算结果。
那么我的思路就是,建立一个散列表,下标是指数,内容是系数(当然,这么做只适用于小范围指数连续的存储,如果是x1+x2000,那就会造成大量的空间浪费,这个时候就需要用结构数组或者链表来存储),这样就很好做这题了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int hashtable[11]={0};
int main(){
	int m;
	while(scanf("%d", &m) != EOF){
		while(m--){
			int n;
			scanf("%d", &n);
			for(int i=0;i<n+1;i++) scanf("%d", &hashtable[i]);
			int x;
			scanf("%d", &x);
			int sum = 0;
			for(int i=0;i<n+1;i++) sum += hashtable[i]*pow(x,i);
			printf("%d\n", sum);
			memset(hashtable, 0, sizeof(hashtable));	
		}
	}
	return 0;
} 

问题 K: 迭代求立方根

题目描述
立方根的逼近迭代方程是 y(n+1) = y(n)2/3 + x/(3y(n)*y(n)),其中y0=x.求给定的x经过n次迭代后立方根的值。
输入
输入有多组数据。
每组一行,输入x n。
输出
迭代n次后的立方根,double精度,保留小数点后面六位。
样例输入

4654684 1
65461 23

样例输出

3103122.666667
40.302088

思路
这题首先的思路是用递归来写,因为题目里直接给出了递归式和递归边界,但是后来发现当迭代23次的时候,递归会爆栈,根本无法出结果,于是这题只能用循环来写……
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
double y(double n, double x){//对x迭代n次 
	double sum = x;//y(0)=x
	for(int i=0;i<n;i++) sum = sum*2.0/3+x/(3*sum*sum);
	return sum;
}
int main(){
	double x, n;
	while(scanf("%lf%lf", &x, &n) != EOF){
		printf("%.6f\n", y(n,x));
	}
	return 0;
} 

问题 L: 与7无关的数

题目描述
一个正整数,如果它能被7整除,或者它的十进制表示法中某个位数上的数字为7,
则称其为与7相关的数.现求所有小于等于n(n<100)的与7无关的正整数的平方和。
输入
案例可能有多组。对于每个测试案例输入为一行,正整数n,(n<100)
输出
对于每个测试案例输出一行,输出小于等于n的与7无关的正整数的平方和。
样例输入

6
12
18

样例输出

91
601
1575

思路
思路很简单,写一个判断是否与7有关的函数,如果能被7整除,返回true(说明与7有关),然后用sprintf将输入的整数转化为字符串,再对字符串逐位判断是否等于字符’7’,如果是,返回true,最后如果两者都没有返回值,说明与7无关,返回false。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
bool judge(int n){
	char tmp[3]={0};
	sprintf(tmp, "%d", n);
	if(n%7==0) return true;
	else{
		for(int i=0;i<strlen(tmp);i++) if(tmp[i]=='7') return true;	
	}
	return false;
}
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		int sum = 0;
		for(int i=1;i<=n;i++){
			if(judge(i)==false) sum += pow(i,2);
		}
		printf("%d\n", sum);
	}
	return 0;
} 

问题 M: 鸡兔同笼

题目描述
一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,每行一个正整数a (a < 32768)
输出
输出包含n行,每行对应一个输入,包含两个正整数,第一个是最少的动物数,第二个是最多的动物数,两个正整数用一个空格分开
如果没有满足要求的答案,则输出两个0。
样例输入

2
18
5

样例输出

5 9
0 0

提示
这个问题可以描述成任给一个整数 N,如果N 是奇数,输出0 0,否则如果N 是4 的倍数,
输出N / 4 N / 2,如果N 不是4 的倍数,输出N/4+1 N/2。这是一个一般的计算题,
只要实现相应的判断和输出代码就可以了。题目中说明了输入整数在一个比较小的范围内,
所以只需要考虑整数运算就可以了。
思路
这题很简单,首先,脚的总数肯定是偶数个,如果是奇数,就说明无解,输出0 0,如果是偶数的话,要最少只动物,那就除4(如果不是4的倍数的话,肯定会余2,说明还有一只鸡,如果是4的倍数的话,就全都是兔子),要最多只动物,那就除2。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<algorithm>
using namespace std;
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		while(n--){
			int a;
			scanf("%d", &a);
			if(a%2!=0) printf("0 0\n");
			else if(a%4==2) printf("%d %d\n", a/4+1, a/2);
			else printf("%d %d\n", a/4, a/2);	
		}
	}
	return 0;
} 

小结

总的来说,这类问题还是比较简单的,我个人觉得主要能分为两类:
一类是用常见的数学概念让你算一些东西,比如矩阵乘积鸡兔同笼百钱百鸡问题等等,这种问题一般都不会涉及太深的数学知识,只要分析好就能写出来;
还有一类是题目会规定一些数或者运算规则,比如众数反序数abc+bcc等等,这一类题目的话只要按照题目的意思写,也不会有太大的问题。

发布了54 篇原创文章 · 获赞 27 · 访问量 4996

猜你喜欢

转载自blog.csdn.net/weixin_42257812/article/details/105099986
今日推荐