【算法】算法中的趣味数学(二)
求π的近似算法
用两种方法编程求π的近似值。
实例解析:
1、用“正多边形逼近”的方法求出π的近似值
我国的祖冲之就是用这种方法在世界上第一个得到精确度达小数点后第6位π值的。
利用圆的内接正六边形边长等于半径特点将边数翻番,做出正十二边形,求出边长,重复这个过程,就可获得所需精度的π的近似值。
假设单位圆的内接多边形的边长为2b,边数为i,则边数加倍后新的正多边形的边长为:
周长为2ix (其中i为加倍前的正多边形的边数)
2、利用随机数法求π的近似值
基本思路是:在一个单位边长的正方形中,以边长为半径,以一个顶点为圆心,在正方形上做四分之一圆。随机向正方形内扔点,若落入四分之一圆内则计数。重复向正方形内扔足够多的点,将落入四分之一圆内的计数除以总的点数,其值就是π值四分之一的近似值。
程序如下:
#include <stdio.h> #include <math.h> #include <time.h> #include <stdlib.h> #define N 30000 int main() { double e = 1.0, b = 0.5, c, d; //e为边长,b为边长的一半 long int i; //i: 正多边形边数 float x, y; int c2 = 0, d2 = 0; puts("\n >> Result of Regular Polygon Approximating:"); for(i = 6; ; i *= 2) { //正多边形边数加倍 d = 1.0 - sqrt(1.0 - b*b); b = 0.5 * sqrt(b*b + d*d); //b为新多边形边长的一半 if(2*i*2*b – i*e < 1e-15) break; //精度达1e-15则停止计算 e = 2*b; //保存新多边形的边长 } printf("-----------------------------------------\n"); /*以下输出π值和正多边形的边数*/ printf(">>pi=%.15lf\n",2*i*b); printf(">>The number of edges of required polygon:%ld\n",i); printf("-----------------------------------------\n"); randomize(); while(c2++ <= N) { x = random(101); //x:坐标。 y = random(101); //y:坐标。 if(x*x + y*y <= 10000) //判断点是否落在圆内 d2++; } puts("\n >> Result of Random Number Method:"); printf("----------------------------------------\n"); printf(" >> pi=%f\n",4.*d2/N); //输出求出的π值 printf("----------------------------------------\n"); puts("\n Press any key to quit..."); getch(); return 0; }
角谷猜想
日本一位学生发现一个奇妙的“定理”,请角谷教授证明,而教授无能为力,于是产生角谷猜想。猜想的内容是:任意给一个自然数,若为偶数则除以2,若为奇数则乘3加1,得到一个新的自然数,然后按照上面的法则继续演算,若干次后得到的结果必然为1。请编程验证。
实例解析:
题目给出的处理过程很清楚,直接进行验证即可。
程序如下:
#include <stdio.h> int main() { int n, count = 0; printf(">>Please input a number to verify(0 to quit):"); scanf("%d",&n); //输入任一整数 while(n != 0) { printf(">>------Results of verification:-------\n"); do { if(n % 2) { n = n*3 + 1; //若为奇数,n乘3加1 printf(">>Step No.%d: %d*3+1=%d\n",++count,(n-1)/3,n); } else { n /= 2; //若为偶数n除以2 printf(">>Step No.%d: %d/2=%d\n",++count,2*n,n); } }while(n != 1); //n不等于1则继续以上过程 printf(">> ----------------------- ----------\n"); printf(">>Please input a number to verify(0 to quit):"); scanf("%d",&n); //输入任一整数 } puts("\n Press any key to quit..."); getch(); return 0; }
四方定量
数论中著名的“四方定理”讲的是:所有自然数至多只要用4个数的平方和就可以表示,请编程验证此定理。
实例解析:
对4个变量采用穷举试探的方法进行计算,满足要求时输出计算结果。
程序如下:
#include <stdio.h> void verify_four_squares(int number) { int i,j,k,n; for(i = 1; i < number/2; i++) //穷举法。试探i,j,k,n的不同值 for(j = 0; j < i; j++) for(k = 0; k < j; k++) for(n = 0; n < k; n++) if(number == i*i + j*j + k*k + n*n) { printf(">>%d=%d*%d+%d*%d+%d*%d+%d*%d\n", number,i,i,j,j,k,k,n,n); return; } } int main() { int number = 1; while(number != 0) { printf(">>Please input a number to verify(0 to quit):"); scanf("%d",&number); //输入任一整数 if(number == 0) break; printf(">>------Results of verification: ----\n"); verify_four_squares(number); printf(">>-----------------------------------\n"); } puts("\n Press any key to quit..."); getch(); return 0; }
卡布列克常数
任意一个4位数,只要他们各个位上的数字是不完全相同的,就有如下规律:
将组成该4位数的4个数字由大到小排列,形成由这4个数字构成的最大的4位数;
将组成该4位数的4个数字由小到大排列,形成由这4个数字构成的最小的4位(如果4位数中含有0,则得到的数不足4位);
求两个数的差,得到一个新的4位数(高位零保留)
重复以上过程,最后得到的结果是6174,这个数被称为卡布列克数。请编程验证卡布列克数。
实例解析:
题目给出的处理过程很清楚,可按题目叙述直接进行验证。
程序如下:
#include <stdio.h> void vr6174(int); void parse_sort(int num, int *each); void max_min(int *each, int *max, int *min); void parse_sort(int num, int *each); int count = 0; int main() { int n = 1; while(n != 0) { printf(">>Please input a 4-digit number to verify(0 to quit): "); scanf("%d",&n); //输入任一整数 if(n == 0) break; printf(">>-----Results of verification: ------\n"); count = 0; vr6174(n); //调用函数进行验证 printf(">> ----------------------------------\n"); } puts("\n Press any key to quit..."); getch(); return 0; } void vr6174(int num) { int each[4], max, min; if(num != 6174 && num) { //若不等于6174且不等于0则进行运算 parse_sort(num,each); //将整数分解,数字存入each数组中 max_min(each,&max,&min); //求数字组成的最大值和最小值 num = max - min; //求最大值和最小值的差 printf(">> Step No.%d: %d-%d=%d\n",++count,max,min,num); //输出该步计算过程 vr6174(num); //递归调用自身继续进行卡布列克运算 } } void parse_sort(int num,int *each) { int i,*j,*k,temp; for(i = 0; i <= 4; i++) { //将NUM分解为数字 j = each + 3 - i; *j = num%10; num /= 10; } for(i = 0; i < 3; i++) //对各数字从小到大进行排序 for(j=each,k=each+1; j < each+3-i; j++,k++) if(*j > *k) { temp = *j; *j = *k; *k = temp; } return; } //下面函数将分解的数字还原为最大整数和最小整数 void max_min(int *each, int *max, int *min) { int *i; *min = 0; for(i = each; i < each+4; i++) //还原为最小的整数 *min = *min * 10 + *i; *max = 0; for(i = each+3; i >= each; i--) //还原为最大的整数 *max = *max * 10 + *i; return; }
本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1171361