关于数学上特殊数(如质数、素数)的笔试题

1 计算N以内的素数

注意:代码部分参考了http://www.cnblogs.com/ladd/archive/2011/05/18/2562100.html和http://blog.csdn.net/haoni123321/article/details/7930827

前提知识:素数又称为质数,指的是只能被1或本身整除的数;

                     任何合数肯定能转化成若干质数的乘积

方法1:

原理是:由于合数能转化成若干质数的乘积,所以质数的倍数肯定不是质数。而且每个合数肯定是小于自己的质数的倍数,所以下面程序中标记为语句1的句子在判断一个数是否是质数时,如果仍然是质数,那么他肯定就不是合数了

  1. int count=0;  
  2. bool *temp=new bool[data];  
  3. for(int i=0;i!=data;++i)  
  4.     temp[i]=true;//用来判断是否是素数的数组  
  5. temp[2]=true;  
  6. for(int i=2;i!=data/2;++i)  
  7. {  
  8.     if(temp[i])  //语句1
  9.     {  
  10.         int j=2;  
  11.         while(i*j<data)//素数的倍数都不是素数  
  12.         {  
  13.             temp[i*j]=false;  
  14.             ++j;  
  15.         }  
  16.     }  
  17. }  
  18. for(int i=2;i!=data;++i)  
  19. {  
  20.     if(temp[i])  
  21.         ++count;  
  22. }  
  23. int *prime=new int[count];//动态分配数组用来保存所有的素数  
  24. count=0;  
  25. for(int i=2;i!=data;++i)  
  26. {  
  27.     if(temp[i]) prime[count++]=i;  
  28. }  
  29.   
  30. delete[] temp;//这两行放在最后释放内存  
  31. delete[] prime;  

方法2:

方法1 存在一个缺陷:每个质数的倍数都是合数,这样导致很多合数被重复判断

每个合数肯定有一个相对于自己的最小质数因子,即合数=相对的最小因子*倍数,所以方法1中没必要将一个素数乘以很大的倍数去排除一个数不是素数

为什么下面的程序不会漏判断一个合数呢:

归根到底的原因在于:每个数等于小于自己数的乘积。

  1. const int MAXN = 100;  
  2. bool flag[MAXN];  
  3. int primes[MAXN / 3], pi;  
  4. void GetPrime_2()  
  5. {  
  6.     int i, j;  
  7.     pi = 0;  
  8.     memset(flag, falsesizeof(flag));  
  9.     for (i = 2; i < MAXN; i++)  
  10.     {  
  11.         if (!flag[i])  
  12.             primes[pi++] = i;  
  13.         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)  
  14.             flag[i * primes[j]] = true;  
  15.     }  
  16. }  

方法3:每个合数必有一个最小素因子,根据每个最小素因子去访问合数就能防止合数被重复访问

  1. const int MAXN = 100;  
  2. bool flag[MAXN];  
  3. int primes[MAXN / 3], pi;  
  4. void GetPrime_2()  
  5. {  
  6.     int i, j;  
  7.     pi = 0;  
  8.     memset(flag, falsesizeof(flag));  
  9.     for (i = 2; i < MAXN; i++)  
  10.     {  
  11.         if (!flag[i])  
  12.             primes[pi++] = i;  
  13.         for (j = 0; (j < pi)  && (i * primes[j] < MAXN); j++)  
  14.         {  
  15.             flag[i * primes[j]] = true;  
  16.             if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次  
  17.                 break;  
  18. }  
  19.     }  
  20. }  
2 质数因子

题目要求:从大到小输出一个数的质数因子

int main()
{
	int N=0;
	while (cin>> N)
	{
		int a=2;
		while (N>=a)
		{
			while(N%a)
				a++;
			cout<<a<<" ";
			N=N/a;
		}
	}
	return 0;
} 
3 公约数

题目要求:计算2个或多个树的最大公约数

题目1:计算两个数的公约数

算法:用大数除以小数,若整除则小数是最大公约数,若不整除,取小数和余数,求他们的一轮的公约数,一次循环,直到能整除

  1. int gcd(int a,int b)  
  2. {  
  3.     return a%b?gcd(b,a%b):b;  
变式1 求多个数的公约数

  1. int gcd(int a,int b)  
  2. {  
  3.     return a%b?gcd(b,a%b):b;  
  4.   
  5. int main()  
  6. {  
  7.     int N,a[20],k,i;  
  8.     while(~scanf("%d",&N))  
  9.     {  
  10.         for(i=0;i<N;i++)  
  11.             scanf("%d",&a[i]);  
  12.   
  13.         k=a[0];  
  14.         for(i=1;i<N;i++)  
  15.         {  
  16.             k=gcd(k,a[i]);  
  17.         }  
  18.   
  19.         printf("%d\n",k);  
  20.     }  
  21.     return 0;  
  22. }
变式2 求两个数的所有公约数

目前只想到比较笨的方法

#include<stdio.h> 
void  main() {
     int  m,n;
     int  i;
     printf ( "input m,n: " );
     scanf ( "%d %d" , &m,&n );
     if  ( m > n )
     {
         i=n;
         n=m;
         m=i;
     }
     for ( i=1;i<=m;i++ )
     {
         if  ( m%i ==0 && n%i==0 )
             printf ( "%d " ,i);
     }
     printf ( "\n" );
}

4 最小公倍数

算法:两个数分别为m和n,其最大公约数为t,则最小公倍数为:m*n/t

此算法可以推广到多个数的最小公倍数

5 一个数的所有因子

题目1 求一个数的因数的个数

注意:如果一个数不是某个数的平方那么其因数的个数必然是偶数个

复杂度高的方法:

int main()
{
	int N=0;
	while (cin>> N)
	{
		int count =0;
		for (int i=1;i<=N;i++)
		{
			for (int j=1;j<=N;j++)
			{
				if (i*j==N)
				{
					count++;
				}
			}
		}
		cout<<count<<endl;
	}
	return 0;
}
改进:

int main()
{
	int N=0;
	while (cin>> N)
	{
		int count =0;
		for (int i=1;i<=N;i++)
		{
			if (N/i<i)
			{
				break;
			}
			if (N%i==0)
			{
				if (N/i==i)
				{
					count++;
				}
				else
				{
					count+=2;
				}	
			}
		}
		cout<<count<<endl;
	}
	return 0;
}
变式1 :

题目:求小于N的数每个数的公因数的个数:

  1. for(i=1;i<=N;i++)  
  2. {  
  3.    for(j=1;j<=N;j++)  
  4.    {  
  5.         if(i*j>N)  
  6.           break;  
  7.        a[i*j]++;  
  8.     }  
  9. }  

变式2:

题目:长廊里依次装有n(1≤n≤65535)盏电灯,从头到尾编号1、2、3、…n-1、n。每盏电灯由一个拉线开关控制。开始,电灯全部关着。

有n个学生从长廊穿过。第一个学生把号码凡是1的倍数的电灯的开关拉一下;接着第二个学生把号码凡是2的倍数的电灯的开关拉一下;接着第三个学生把号码凡是3的倍数的电灯的开关拉一下;如此继续下去,最后第n个学生把号码凡是n的倍数的电灯的开关拉一下。n个学生按此规定走完后,长廊里电灯有几盏亮着。

分析: 对于任何一盏灯,由于它原来不亮,那么当它的开关被按奇数次时,灯是开着的;当它的开关被按偶数次时,灯是关着的;一盏灯的开关被按的次数,恰等于这盏灯的编号的因数的个数要求哪些灯还亮着,就是问哪些灯的编号的因数有奇数个显然完全平方数有奇数个因数。每个数除以一个数A等于另一个数B,那么A和B都是它的因数,于是因数是成对出现的,但是要因数是奇数,就必须它的两个因数A=B,才能使它的因数有奇数个。
  1. include <iostream>  
  2. using namespace std;  
  3. int main(){  
  4.     int i;  
  5.     int N;  
  6.     int count;  
  7.     while(cin>>N){  
  8.         count=0;  
  9.         for(i=1;;i++){  
  10.             if(i*i>N)  
  11.                 break;  
  12.             count++;  
  13.         }  
  14.         cout<<count<<endl;  
  15.     }  
  16.     return 0;  
  17. }  

6 丑数


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值