模拟算法
什么是模拟算法
模拟算法主要是利用计算机对真实或者虚拟的过程进行模拟,来寻找和评估不同的方案或决策。
通俗的说,模拟算法就是在计算机上模拟实际问题,通过模拟得到的结果,进行预测和决策。
模拟算法的特点
- 直观性强
- 灵活性强
- 复杂度高
实现过程
模拟算法通常需要分析模拟的过程,模拟过程中可能会有不同的状态和转移,因此分析模拟算法的过程包括以下几个步骤:
- 确定模拟过程
- 确定状态
- 确定状态转移
- 编写代码实现模拟
高精度计算
利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。介绍常用的几种高精度计算的方法。
高精度加法。输入两个正整数,求它们的和。
(1)数据的接收方法和存贮方法
数据的接收和存贮:当输入的数据很长时,可采用字符串方式输入,这样可输入数字很长的数,利用字符串函数和操作运算,将每一位数取出,存入数组中。另一种方法是直接用循环加数组方法输入数据。
void init(int a[])
{
string s;
cin>>s;
a[0] = s.length();
for(i=1;i<=a[0];i++)
a[i] = a[a[0] - i] - '0';
}
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210;
char s1[N],s2[N];
int a[N],b[N],c[N];
int main()
{
int len1,len2,len,jw;
scanf("%s %s",s1,s2);
len1=strlen(s1);
len2=strlen(s2);
for(int i=0;i<len1;i++)
a[i] = s1[len1 - i - 1] - '0';
for(int i=0;i<len2;i++)
b[i] = s2[len2 - i - 1] - '0';
len = max(len1,len2) + 1;
jw = 0;
for(int i=0;i<len;i++)
{
c[i] = a[i]+b[i]+jw;
jw = c[i]/10;
c[i] %= 10;
}
for(int i = len -1;i>=0;i--)
{
if(c[i] == 0 && len>1) len--;
else break;
}
for(int i = len -1;i>=0;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
(2)高精度数位数的确定
位数的确定:接收时往往是用字符串的,所以它的位数就等于字符串长度。
(3)进位,借位处理
加法进位:c[i] = a[i] + b[i];
if(c[i] >= 10) {c[i]%10;++c[i+1];}
减法借位:if(a[i] < b[i]) {–a[i+1];i[i] += 10;}
c[i] = a[i] - b[i];
乘法进位:
c[i+j - 1]=a[i]* b [*]+ x+c[i+j - 1];
x=c[i+j-1]/10;
c[i+j-1]%=10;
(4)商和余数的求法
商和余数的处理:视被除数和除数的位数情况进行处理。
高精度乘法
输入两个正整数,求它们的积。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char s1[101],s2[101];
int a[101],b[101],c[10001],len1,len2,len,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%s %s",s1,s2);
len1 = strlen(s1);
len2 = strlen(s2);
for(int i=0;i<=len1-1;i++) a[len1 - i]= s1[i] - '0';
for(int i=0;i<=len2-1;i++) b[len2 - i]=s2[i]-'0';
for(int i=1;i<=len1;i++)
{
x = 0;
for(int j=1;j<=len2;j++)
{
c[i+j-1] = a[i]*b[j] +x +c[i+j - 1];//当前乘积+上次乘积的进位+原数
x=c[i+j-1]/10;
c[i+j-1]%=10;
}
c[i+len2] =x;
}
len = len1+len2;
while(c[len]==0 && len>1)
len--;
for(int i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
例6 回文数
【问题描述】若一个数(首位不为零)从左向右读与从右向左读都是一样我们就将其称为回文数。例如,给定一个10进制数56,将56加65,得到121是一个回文数。又如,对于10进制数87,
setp1:87+78=165
setp2:165+561=726
setp3:726+627=1353
setp4:1353+3531=4884
在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884
写一个程序,给定一个N(2<N<=10或N=16)进制数M,求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出"Impossible"
#include<iostream>
#include<cstring>
using namespace std;
#define N 105
int n,a[N];
char s[N];
bool check(int a[]){
for (int i=1;i<=a[0]/2;i++)
{
if(a[i] != a[a[0]-i+1]) return false;
}
return true;
}
void getOpp(int a[],int b[])
{
for(int i=1;i<=a[0];i++)
{
b[i]=a[a[0]-i+1];
}
b[0] = a[0];
}
void addAB(int a[],int b[])
{
int c=0;
for(int i=1;i<=a[0];i++)
{
a[i]+=b[i]+c;
c=a[i]/n;
a[i]%=n;
}
if(c>0)
{
a[0]++;
a[a[0]]=c;
}
}
int main()
{
int b[N]={};
cin>>n>>s;
int len=strlen(s);
for(int i=1;i<=len;i++)
{
if(s[len-i]>='0' && s[len-i]<='9')
a[i]=s[len-i]-'0';
else
a[i]=s[len-i]-'A'+10;
}
a[0]=len;
for(int i=0;i<=30;i++)
{
if(check(a))
{
cout<<i;
return 0;
}
getOpp(a,b);
addAB(a,b);
}
cout<<"Impossible";
return 0;
}