1 计算N以内的素数
注意:代码部分参考了http://www.cnblogs.com/ladd/archive/2011/05/18/2562100.html和http://blog.csdn.net/haoni123321/article/details/7930827
前提知识:素数又称为质数,指的是只能被1或本身整除的数;
任何合数肯定能转化成若干质数的乘积
方法1:
原理是:由于合数能转化成若干质数的乘积,所以质数的倍数肯定不是质数。而且每个合数肯定是小于自己的质数的倍数,所以下面程序中标记为语句1的句子在判断一个数是否是质数时,如果仍然是质数,那么他肯定就不是合数了
- int count=0;
- bool *temp=new bool[data];
- for(int i=0;i!=data;++i)
- temp[i]=true;//用来判断是否是素数的数组
- temp[2]=true;
- for(int i=2;i!=data/2;++i)
- {
- if(temp[i]) //语句1
- {
- int j=2;
- while(i*j<data)//素数的倍数都不是素数
- {
- temp[i*j]=false;
- ++j;
- }
- }
- }
- for(int i=2;i!=data;++i)
- {
- if(temp[i])
- ++count;
- }
- int *prime=new int[count];//动态分配数组用来保存所有的素数
- count=0;
- for(int i=2;i!=data;++i)
- {
- if(temp[i]) prime[count++]=i;
- }
- delete[] temp;//这两行放在最后释放内存
- delete[] prime;
方法2:
方法1 存在一个缺陷:每个质数的倍数都是合数,这样导致很多合数被重复判断
每个合数肯定有一个相对于自己的最小质数因子,即合数=相对的最小因子*倍数,所以方法1中没必要将一个素数乘以很大的倍数去排除一个数不是素数
为什么下面的程序不会漏判断一个合数呢:
归根到底的原因在于:每个数等于小于自己数的乘积。
- const int MAXN = 100;
- bool flag[MAXN];
- int primes[MAXN / 3], pi;
- void GetPrime_2()
- {
- int i, j;
- pi = 0;
- memset(flag, false, sizeof(flag));
- for (i = 2; i < MAXN; i++)
- {
- if (!flag[i])
- primes[pi++] = i;
- for (j = 0; (j < pi) && (i * primes[j] < MAXN); j++)
- flag[i * primes[j]] = true;
- }
- }
方法3:每个合数必有一个最小素因子,根据每个最小素因子去访问合数就能防止合数被重复访问
- const int MAXN = 100;
- bool flag[MAXN];
- int primes[MAXN / 3], pi;
- void GetPrime_2()
- {
- int i, j;
- pi = 0;
- memset(flag, false, sizeof(flag));
- for (i = 2; i < MAXN; i++)
- {
- if (!flag[i])
- primes[pi++] = i;
- for (j = 0; (j < pi) && (i * primes[j] < MAXN); j++)
- {
- flag[i * primes[j]] = true;
- if (i % primes[j] == 0) //这句保证每个非素数只被筛去一次
- break;
- }
- }
- }
题目要求:从大到小输出一个数的质数因子
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:计算两个数的公约数
算法:用大数除以小数,若整除则小数是最大公约数,若不整除,取小数和余数,求他们的一轮的公约数,一次循环,直到能整除
- int gcd(int a,int b)
- {
- return a%b?gcd(b,a%b):b;
- }
- int gcd(int a,int b)
- {
- return a%b?gcd(b,a%b):b;
- }
- int main()
- {
- int N,a[20],k,i;
- while(~scanf("%d",&N))
- {
- for(i=0;i<N;i++)
- scanf("%d",&a[i]);
- k=a[0];
- for(i=1;i<N;i++)
- {
- k=gcd(k,a[i]);
- }
- printf("%d\n",k);
- }
- return 0;
- }
目前只想到比较笨的方法
#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的数每个数的公因数的个数:
- for(i=1;i<=N;i++)
- {
- for(j=1;j<=N;j++)
- {
- if(i*j>N)
- break;
- a[i*j]++;
- }
- }
变式2:
题目:长廊里依次装有n(1≤n≤65535)盏电灯,从头到尾编号1、2、3、…n-1、n。每盏电灯由一个拉线开关控制。开始,电灯全部关着。
有n个学生从长廊穿过。第一个学生把号码凡是1的倍数的电灯的开关拉一下;接着第二个学生把号码凡是2的倍数的电灯的开关拉一下;接着第三个学生把号码凡是3的倍数的电灯的开关拉一下;如此继续下去,最后第n个学生把号码凡是n的倍数的电灯的开关拉一下。n个学生按此规定走完后,长廊里电灯有几盏亮着。
分析: 对于任何一盏灯,由于它原来不亮,那么当它的开关被按奇数次时,灯是开着的;当它的开关被按偶数次时,灯是关着的;一盏灯的开关被按的次数,恰等于这盏灯的编号的因数的个数;要求哪些灯还亮着,就是问哪些灯的编号的因数有奇数个.显然完全平方数有奇数个因数。每个数除以一个数A等于另一个数B,那么A和B都是它的因数,于是因数是成对出现的,但是要因数是奇数,就必须它的两个因数A=B,才能使它的因数有奇数个。- include <iostream>
- using namespace std;
- int main(){
- int i;
- int N;
- int count;
- while(cin>>N){
- count=0;
- for(i=1;;i++){
- if(i*i>N)
- break;
- count++;
- }
- cout<<count<<endl;
- }
- return 0;
- }
6 丑数