您的位置:首页 > 编程语言 > C语言/C++

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

2017-03-09 10:18 465 查看

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

引言 

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

写个算法,对 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息