信息学奥赛一本通 1308 高精除

1308:【例1.5】高精除


时间限制: 1000 ms         内存限制: 65536 KB
提交数:25526    通过数: 12451

【题目描述】

高精除以高精,求它们的商和余数。

【输入】

输入两个低于300位的正整数。

【输出】

输出商和余数。

【输入样例】

1231312318457577687897987642324567864324567876543245671425346756786867867867
1231312318767141738178325678412414124141425346756786867867867

【输出样例】

999999999748590
179780909068307566598992807564736854549985603543237528310337
#include <bits/stdc++.h>
using namespace std;
char str1[305];//字符串储存 被除数 
char str2[305];//字符串储存 除数 
int temp[305];//补齐0后 临时数组 
int num1[305];//数组储存 被除数 
int num2[305];//数组储存 除数 
int ans[305]; //数组储存 商
void numcpy(int *num1,int *num2,int dest)//补齐函数
{
	//右移 左边空出dest个位置 补齐0
	for(int i=1;i<=num1[0];i++)//num1实际上代表除数
	{
		num2[i+dest-1]=num1[i];//num2实际上代表temp 
	 } 
	num2[0]=num1[0]+dest-1;//temp数组变更长度 
 } 
int compare (int *num1,int*num2)//比较函数
//引入 被除数 除数
{
	//一 比较数字长度 
	if (num1[0]<num2[0])//除数 大于 被除数 
	{
		return -1;
	}
	else if (num1[0]>num2[0])//被除数 大于 除数 
	{
		return 1; 
	}
	//二 数字长度相同 比较每一位
	for(int i=num1[0];i>0;i--)//高-低位 循环比较
	{
		if (num1[i]<num2[i])//除数 大于 被除数
		{
			return -1; 
		 } 
		else if (num1[i]>num2[i])//被除数 大于 除数
		{
			return 1;
		 }  
	 } 
	return 0;//大小相同 
 } 
int main()
{
	cin >> str1;//被除数 字符串输入 
	cin >> str2;//除数 字符串输入 
	//处理正负 
	bool flag1=false;//储存num1正负
	if (str1[0]=='-')//输入str1有负号 
	{
		flag1=true;//储存num1为负数
		strcpy(str1,&str1[1]);//覆盖负号 
	 }
	bool flag2=false;//储存num2正负
	if(str2[0]=='-')//输入str2有负号
	{
		flag2=true;//储存num2为负数 
		strcpy(str2,&str2[1]);//覆盖负号 
	  }
	//数据倒序
	int len=strlen(str1);//测量 被除数 长度
	num1[0]=len;//预留 num1第0位 储存 被除数长度
	for (int i=0;i<len;i++)//倒序 转数组 
	{
		num1[len-i]=str1[i]-'0';
	  }  
	len=strlen(str2);//测量 除数长度
	num2[0]=len;//同上 
 	for (int i=0;i<len;i++)//倒序 转数组
	{
		num2[len-i]=str2[i]-'0';
	  }  
	if (compare(num1,num2)==0)//被除数=除数
	{
		cout << 1 << endl << 0 << endl;
		//打印 商=1 余数=0  
		return 0; 
	  }
	else if (compare(num1,num2)==-1)//除数 大于 被除数
	{
		//商=0 余数为被除数
		cout << 0 << endl;//输出商
		if (flag1)//被除数=余数 为负数
		{
			cout << "-";//输出负号 
		 } 
		cout << str1 << endl;//输出 被除数字符串 已去负号  
	  }  	    
	else//被除数 大于 除数 
	{
		ans[0]=num1[0]-num2[0]+1;//商预计长度
		for (int i=ans[0];i>0;i--)//倒序处理答案
		{
			//利用临时数组temp补0对齐
			memset (temp,0,sizeof(temp));//初始化temp为0
			numcpy(num2,temp,i);//除数放入临时数组进行对齐 
			//逐步进行减运算 当 temp 小于 被除数 一直减
			while(compare(num1,temp)>=0)
			//被除数大于temp进行运算 
			{
				ans[i]++;//商加1
//				cout << "dfafadsf" << endl;
				for(int j=1;j<=num1[0];j++)//逐步进行减运算 
				//循环 被除数长度 次
				{
					if (num1[j]<temp[j])//判断是否需要进位
					{
						num1[j+1]--;
						num1[j]+=10;//进位 
					 } 
					num1[j]-=temp[j];//被除数-除数 
					
				  } 
				int tempk=num1[0];//定义临时 被除数位数
				while(num1[tempk]==0)//判断高位是否为0
				{
					tempk--;//临时位数变短 
				}
				num1[0]=tempk;//变更被除数位数  
			 } 
		 } 
	  } 
	//运算完成输出结果
	while(ans[0]>0&&ans[ans[0]]==0)//去除前导0
	//商不为0 有前导0 
	{
		ans[0]--;//位数变短 不输出前导0 
	  }  
	//打印商 余数
	if (!flag1 && flag2 || flag1 && !flag2)//被除数 除数有一个为负数->商为负数 
	{
		cout << "-";//输出负数 
	  }  
	for(int i=ans[0];i>0;i--)//倒序输出商
	{
		cout << ans[i];
	  }  
	cout << endl;//换行 
	if (num1[0]==0)//被除数无剩余=无余数
	{
		cout << 0 << endl;
		return 0; 
		  }	  
	else//有余数 
	{
		if(flag1)//被除数剩余=余数 为负数
		{
			cout << "-";//输出负号 
		 } 
		for (int i=num1[0];i>0;i--)//倒序输出余数
		{
			cout << num1[i];
		 } 
		 cout << endl;
		  }	  
	return 0;
 }

这段代码很长且不好理解 一定要搞清楚 很重要

### 问题分析 信息学奥赛一本1308题的题目名称为“最少步数”,属于广度优先搜索(BFS)的经典应用。题目要求在给定的二维迷宫中,从起点(0,0)走到终点(n-1,m-1)所需的最小步数。迷宫由0和1组成,其中0表示可以行,1表示障碍物。 该问题的核心在于寻找最短路径,而BFS算法天然适合此类问题,因为它按层扩展,确保第一次到达终点时所用的步数最少。 ### 解题思路 - 使用一个队列存储待访问的点,并维护一个二维数组记录是否访问过某个位置。 - 起点加入队列,并标记为已访问。 - 每次从队列中取出一个点,尝试向四个方向移动(上、下、左、右)。 - 若新位置未越界、可行且未访问,则将其加入队列,并标记为已访问。 - 每层BFS对应一步,直到到达终点为止。 ### 参考代码 ```cpp #include <bits/stdc++.h> using namespace std; int n, m; int maze[101][101]; int visited[101][101]; int dx[] = {-1, 1, 0, 0}; int dy[] = {0, 0, -1, 1}; struct Point { int x, y; }; queue<Point> q; int bfs() { q.push({0, 0}); visited[0][0] = 1; int steps = 0; while (!q.empty()) { int size = q.size(); for (int k = 0; k < size; k++) { Point p = q.front(); q.pop(); if (p.x == n - 1 && p.y == m - 1) { return steps; } for (int i = 0; i < 4; i++) { int nx = p.x + dx[i]; int ny = p.y + dy[i]; if (nx >= 0 && nx < n && ny >= 0 && ny < m && maze[nx][ny] == 0 && !visited[nx][ny]) { visited[nx][ny] = 1; q.push({nx, ny}); } } } steps++; } return -1; } int main() { cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> maze[i][j]; } } cout << bfs(); return 0; } ``` ### 测试样例 输入: ``` 3 3 0 1 0 0 1 0 0 0 0 ``` 输出: ``` 6 ``` ### 常见问题与优化 - 需要判断起点或终点是否是障碍物,否则可能导致程序无法正确运行。 - 若未正确维护访问数组,可能导致队列无限增长。 - 队列每层的节点数需单独处理,以确保步数递增的正确性[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值