C 数据结构之分解素因数

1.分解质因数

求正整数N的质因数的个数,相同的质因数需要重复计算。如 120=2*2*2*3*5。对于每组数据,输出N的质因数个数。

样例输入:120  样例输出 5 (1不是N的质因数,若N为质数,则N是N的质因数) 

思路:利用素数筛法预先筛选出所有可能成为给定数据范围内成为素因数的素数。依次遍历所有小于n的素数,判断其是否是n的因数。若是,则通过试除确定对应的幂指数。最后求出各个幂指数的和即为所求。

1.输入n

2.依次测试步骤1中得到的素数能否整除n,若能则表明该素数为他的一个素因数。

3.不断将n除以该素数,直到不能再被整除为止。同时统计其幂指数。

4.若完成某个素数的幂指数统计后,n变为1,则表明n的所有素因数全部被分解出来,分解停止。

5.若遍历、测试、分解完所有预处理的素数,n仍没被除成1,则表明n存在一个大于100000的因子,则该因子必为其素因子,幂指数为1。

#include<stdio.h>
bool mark[100001];
int prime[100001];
int primeSize;
void init()//素筛法 
{
	primeSize=0;
	for(int i=2;i<=100000;i++)
	{
		if(mark[i]==true) continue;
		prime[primeSize++]=i;
		if(i>=1000) continue;
		for(int j=i*i;j<=100000;j+=i)
		{
			mark[j]=true;
		}
	}
} 
int main()
{
	init();
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		int ansPrime[30];//按顺序保存分解出的素因数 
		int  ansSize=0;//分解出素因数的个数 
		int ansNum[30];//保存分解出的素因数对应的个数(幂指数) 
		for(int i=0;i<primeSize;i++)//依次测试每一个素数 
		{
			if(n%prime[i]==0)
			{//若能整除,则为素因数 
				ansPrime[ansSize]=prime[i];
				ansNum[ansSize]=0;
				while(n%prime[i]==0)//从被测试数中将该素数分解出来,并统计其幂指数 
				{
					ansNum[ansSize]++;
					n/=prime[i];
				}
				ansSize++;//素因数个数增加 
				if(n==1)  break;//分解为1,终止 
			}
		}
		if(n!=1)//若测试完所有素数,n仍未被分解为1,则剩余的因数一定是n,一个大于10000的素因数 
		{       //其幂指数只能为1 
			ansPrime[ansSize]=n;
			ansNum[ansSize++]=1;
		}
		int ans=0;
		for(int i=0;i<ansSize;i++)
		ans+=ansNum[i];//统计各个素因数的幂指数 
		printf("%d\n",ans);
	}
	return 0;
}

2.整除问题

给定 n,a求最大的k,使n!可以被a^k整除但不能被a^(k+1) 整除

思路:若整数a能整除整数b:若a存在素因数Px,则b也必存在该素因数。且该素因数在b中对应的幂指数必不小于在a中的幂指数。要确定最大的非负整数k,使a中任一素因数的幂指数的k倍依旧小于或等于该素因数在x中对应的幂指数。要求得k,只需依次测试a中的每一个素数,确定b中该素因数对应的幂指数是a中的几倍(利用整除法),这样所有倍数中最小的那个即为我们要求的k。那么如何对n!分解素因数?步骤如下:

1.计算器清0,该计数器表示n!中将有几个p因子,即n!分解质因数后素因子p对应的幂指数。

2.计算n/p,有n/p个整数可以向n!提供一个p因子,则计数器累加n/p。若n/p为0,不能提供p因子,分解结束。

3.计算n/(p*p),有n/(p*p)个整数可以向n!提供2个p因子,但他们之前步骤中p的倍数必包括p*p的倍数,每个数已经向累加器累加了一个p因子,所以此处提供n/(p*p)个素因子。若为0.分解结束。

4.依次累加p的更高次的倍数能够提供的素因子个数,即每次向计数器累加n/(p^k),直到其变为0,表示没有整数能提供更多的p因子,分解结束。计数器累加的结果即为素因数p的幂指数。

#include<stdio.h> 
#include<string.h>
bool mark[1010];
int prime[1010];
int primeSize;
void init()
{
	primeSize=0;
	for(int i=2;i<10000;i++)
	{
		if(mark[i]) continue;
	//	mark[i]=true;
		prime[primeSize++]=i;
		for(int j=i*i;j<1000;j+=i)
		mark[j]=true;
	}
}//筛选出0到1000范围内的所有素数 
int cnt[1010];//cnt[i]用来表示,prime[i]所保存的素数在n!中的因子数,即prime[i]的幂指数 
int cnt2[1010];//cnt2[i] 来表示,prime[i]所保存的素数在a中的因子数
int main()
{
	int n,a;
	init();
	while(scanf("%d%d",&n,&a)==2)
	{

		for(int i=0;i<primeSize;i++)
		cnt[i]=cnt2[i]=0;//将两个计数器清0,为新一次分解做准备 
		for(int i=0;i<primeSize;i++)//对n!分解素因数,遍历每一个0到1000的素数 
		{
			int t=n;
			while(t)//确定prime[i]在n中的因子数 
			{
				cnt[i]+=t/prime[i];
				t=t/prime[i];
			}//依次计算t/prime[i]^k,累加其值,直到t/prime[i]^k变为0 
		}
		int ans=123123123;
		for(int i=0;i<primeSize;i++)//对a分解素因数 
		{
			while(a%prime[i]==0)
			{
				cnt2[i]++;
				a/=prime[i];
			}//计算a中素因数prime[i]对应的幂指数 
			if(cnt2[i]==0) continue;
			if(cnt[i]/cnt2[i]<ans)//计算prime[i]在两个数中因子数的商 
			ans=cnt[i]/cnt2[i];//统计最小值 
		}
		printf("%d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值