考研复试系列——第九节 数论基础

考研复试系列——第九节 数论基础

引言 


首先引入一道简单的题目来说明一下最近看到的一个小技巧 ,觉得挺不错的 , 该部分内容来源于 《王道论坛》 。

写个算法,对 2 个小于 1000000000 的输入,求结果。
特殊乘法举例:123 * 45 = 1*4 +1*5 +2*4 +2*5 +3*4+3*5

样例输入:
123 45
样例输出:
54

这道题目肯很简单,我们一眼望去想到的思路就是无非是将每一位求出保存起来,然后双重for循环不就好了。
代码如下:
#include<iostream>
using namespace std;

int main()
{
	int a,b;
	while(cin>>a>>b && a && b)
	{
		int buff1[10],buff2[10];
		int size1=0,size2=0;
		while(a!=0)
		{
			buff1[size1++] = a % 10;
			a/=10;
		}
		while(b!=0)
		{
			buff2[size2++] = b % 10;
			b/=10;
		}
		int ans = 0;
		for(int i=0;i<size1;i++)
			for(int j=0;j<size2;j++)
				ans += buff1[i] * buff2[j];
		cout<<ans<<endl;
	}

	return 0;
}
换种思路,加入我们把输入的整数当做字符串输入,处理起来不是简单多了,就不用再一位一位的求保存起来,而可以直接处理。
#include<iostream>
using namespace std;

int main()
{
	char a[11],b[11];
	while(cin>>a>>b && a && b)
	{
		int ans = 0;
		for(int i=0;a[i]!='\0';i++)
			for(int j=0;b[j]!='\0';j++)
				ans += (a[i] - '0') * (b[j] - '0');
		cout<<ans<<endl;
	}
	return 0;
}

这道题本身没有难度,但是通过字符串输入解决问题的思路值得我们学习,想想写大数加法乘法用的不就是这种思路吗。

素数问题


如何判断一个素数 ,这个相信大家都会了,但其常常是其他素数问题的基础,我们再来写一下。
#include<iostream>
#include<cmath>
using namespace std;

bool checkPrime(int n)
{
	if(n <= 1)
		return false;
	int bound = sqrt(n);
	for(int i=2;i<=bound;i++)
		if(n%2 == 0)
			return false;
	return true;
}
int main()
{
	int n;
	cin>>n;
	if(checkPrime(n))
		cout<<n<<"是素数"<<endl;
	else
		cout<<n<<"不是素数"<<endl;
	return 0;
}

素数筛选法

假如我们要求出2到100000之间的所有素数,使用前面的方法一个个判断非常不可,但是从效率上肯定不高。我们考虑这样一种策略,
当我们得到一个素数,那他的倍数肯定不是素数,就把它的倍数标记为非素数,这样当我们遍历到一个数时,它没有被任何小于它的素数
标记为非素数,我们就可以确定这个数是素数。简单举个例子,我们从2开始,2是素数,于是将2的倍数也就是4,6,8,。。。标记为非素数
然后到3,因为3没有被小于它的素数2标记,所以3是素数,于是又将9,12,15.。。。标记为非素数,以此类推我们就得到了一张素数表。

#include<iostream>
#include<cmath>
using namespace std;

#define MAX 100001
int prime[MAX];

void Prime()
{
	int bound = sqrt(MAX);
	for(int i=2;i<=bound;i++)
	{
		if(prime[i] == 0)//如果没有被标记
		{
			for(int j=i*i;j<MAX;j+=i)//这里为什么是i*i要注意,比如当前是9,那么5*9 ,7*9肯定在前面以及被标记过了,所以最小是9*9
				prime[j] = 1;
		}
	}
}

int main()
{
	Prime();
	for(int i=2;i<MAX;i++)
	{
		if(prime[i] == 0)
			cout<<i<<" ";
	}
	cout<<endl;
	return 0;
}

下面来一道例题:

描述:
现在给出你一些数,要求你写出一个程序,输出这些整数相邻最近的素数,并输出其相距长度。如果左右有等距离长度素数,则输出左侧的值及相应距离。
如果输入的整数本身就是素数,则输出该素数本身,距离输出0
输入:
第一行给出测试数据组数N(0<N<=10000)
接下来的N行每行有一个整数M(0<M<1000000),
输出:
每行输出两个整数 A B.
其中A表示离相应测试数据最近的素数,B表示其间的距离。
sample input:
3
6
8
10
sample output:
5 1
7 1
11 1
注意:距离999999最近的素数就是1000003

#include<iostream>
#include<cmath>
using namespace std;

#define MAX 1000010
int prime[MAX];

void Prime()//求素数表
{
	prime[0] = prime[1] = 1;
	int bound = sqrt(MAX);
	for(int i=2;i<=bound;i++)
	{
		if(prime[i] == 0)//如果没有被标记
		{
			for(int j=i*i;j<MAX;j+=i)//这里为什么是i*i要注意,比如当前是9,那么5*9 ,7*9肯定在前面以及被标记过了,所以最小是9*9
				prime[j] = 1;
		}
	}
}

int main()
{
	int N,M;
	Prime();
	cin>>N;
	while(N--)
	{
		cin>>M;
		if(prime[M] == 0){
			cout<<M<<" 0"<<endl;
		}
		else{
			int RIndex = M;
			int LIndex = M;
			while(prime[LIndex] == 1 && LIndex >= 0)//寻找左边素数
				LIndex --;	
			while(prime[RIndex] == 1)//寻找右边素数
				RIndex ++;
			if(LIndex < 0)//左边没有找到
				cout<<RIndex<<" "<<RIndex-M<<endl;		
			else if(M - LIndex <= RIndex - M)//左右都有且左边距离更近
				cout<<LIndex<<" "<<M-LIndex<<endl;
			else
				cout<<RIndex<<" "<<RIndex-M<<endl;//左右都有且右边距离更近
		}
	}
	return 0;
}

二分法求解方程组

题目如下:求f(x)=x^3-x-1在【1,1.5】内的一个实根,使误差不超过0.005。结果保留两位小数。

二分法算法思想:首先确定有根区间,将区间二等分,通过判断f(x)的符号,逐步将有根区间缩小,直至有根区间足够小,便可求出满足精度要求的近似值。
如图所示:

根据流程图写代码:
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;

float calculate(float x)
{
	return x*x*x - x - 1;
}

int main()
{
	float a,b,c,x;//输入区间以及精度
	cin>>a>>b>>c;
	while(fabs(b-a)>=c)
	{
		x = (a+b)/2;
		if(calculate(a) * calculate(x) < 0)
			b = x;
		else
			a = x;
	}
	cout<<"满足条件的值为:"<<fixed<<setprecision(2)<<x<<endl;
	return 0;
}

求三角形的面积

直接套公式就好了 ,高中数学就讲过。
#include<iostream>
#include<cmath>
using namespace std;

float area3(float x1,float y1,float x2,float y2,float x3,float y3)//这里用的坐标,也可以直接根据边长
{
	float a,b,c,p;
	a=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
	b=sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3));
	c=sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
	p=(a+b+c)/2;
	return sqrt(p*(p-a)*(p-b)*(p-c));
}

int main()
{
	float x1,x2,x3,y1,y2,y3;
	cin>>x1>>y1>>x2>>y2>>x3>>y3;
	cout<<area3(x1,y1,x2,y2,x3,y3)<<endl;
	return 0;
}

进制转换

先来一道很简单的题目:输入一个十进制数,将其转换为8进制数并输出 (某某年中科大的上机试题之一)。

#include<iostream>
#include<stack>
using namespace std;

stack<int> s;

void convert(int n)//将十进制数转换为8进制
{
	while(n)
	{
		s.push(n%8);
		n /= 8;
	}
}

int main()
{
	int n;//十进制数
	cin>>n;
	convert(n);
	while(!s.empty())
	{
		int a = s.top();
		cout<<a;
		s.pop();
	}
	cout<<endl;
	return 0;
}
注意 :这里没有考虑0和大整数的问题。

再来看一道题目
10进制转2进制并判断二进制数中1的个数,也是中科大某某年的上机试题。这道也不难。我们可以与上题一样,但是在出栈时判断一下是1就好了。
这里就不给代码了,但我们也可以采取另一种方式直接计算二进制中1的个数。利用移位操作和与运算就能方便的计算了,这个也很简单。记得某某年
的网易的面试题还用过这个方法。

关于欧几里得和素因子分解在我的另一篇博文中:

http://blog.csdn.net/cassiepython/article/details/43154103








猜你喜欢

转载自blog.csdn.net/cassiepython/article/details/60866733