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

来源:互联网 发布:单片机设计大赛 编辑:程序博客网 时间:2024/05/16 07:46

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

引言 


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

写个算法,对 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;elsecout<<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 100001int 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*9prime[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 1000010int 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*9prime[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;elsecout<<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;elsea = 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








1 0
原创粉丝点击