2023年省信息教师培训day17

模拟算法

什么是模拟算法

模拟算法主要是利用计算机对真实或者虚拟的过程进行模拟,来寻找和评估不同的方案或决策。
通俗的说,模拟算法就是在计算机上模拟实际问题,通过模拟得到的结果,进行预测和决策。

模拟算法的特点

  1. 直观性强
  2. 灵活性强
  3. 复杂度高

实现过程

模拟算法通常需要分析模拟的过程,模拟过程中可能会有不同的状态和转移,因此分析模拟算法的过程包括以下几个步骤:

  1. 确定模拟过程
  2. 确定状态
  3. 确定状态转移
  4. 编写代码实现模拟

高精度计算

利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。介绍常用的几种高精度计算的方法。

高精度加法。输入两个正整数,求它们的和。

(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值