PAT乙级(Basic Level)练习题 送外卖(大数乘法,万进制实现)

题目描述
冬天到了,小伙伴们都懒得出去吃饭了,纷纷打电话叫起了外卖。送外卖的小哥想找出一条最短的路径,小区门口进来,送完外卖又回到小区门口。
整个小区是一个由m*n个边长为1的正方形组成的矩形,各幢公寓楼分布于正方型的顶点上,小区门口位于左上角。每幢楼与相邻的八个方向的楼之间都有道路。
下图为m=2,n=3的小区地图,并且外卖小哥要经过的最短路径为6。
在这里插入图片描述
输入描述:
输入有多组数据。
每组数据包含两个整数m (2≤n≤2128) 和n (2≤r≤2128),分别代表行数和列数。

输出描述:
对应每一组数据,输出外卖小哥需要经过的最短路径。结果保留两位小数。

输入例子:

2 2
3 3

输出例子:

4.00
9.41

\color{blue}解题思路:
这道题问的是让你找出访问所有楼栋需要的最短路径。
下面是评论区找出的结论。
在这里插入图片描述
在这里插入图片描述
这个结论还是比较难想到的,尤其是证明它为最优路径。

由于输入整数m (2≤n≤2128) 和n (2≤r≤2128)范围非常大,因此我们需要手动写一个大数乘法器。没办法,C艹库少。。。

我采用的是万进制逢万进一
输入的是数值字符串,比如"12345601230009",然后转换成int数组intsNum[4, 9, 123, 3456, 12],intsNum[0]表示数组的长度,intsNum[1]=9表示数值字符串中的第一段“0999”,intsNum[2]=123,表示数组中的第二段0123intsNum[3]=3456,表示数组中的第三段3456intsNum[4]=12,表示数组中的第四段12
在这里插入图片描述

\color{blue}代码实现:

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

//将两个数组相乘,并且结果存放子啊num3
//数组示例[4,123,0,1234,9],4表示长度,真正表示是的值为 ‘9 1234 0000 0123’
void bigNumMutli(int* num1, int* num2, int* num3, int maxLen) {
	memset(num3, 0, maxLen);
	//1、对num1、num2进行相乘
	for (int i = 1; i <= num2[0]; ++i) {
		for (int j = 1; j <= num1[0]; ++j) {
			//num1的第j位 与 num2的第i位相乘,应该放在num3的 第i + j - 1位上,画一个多位数相乘算术式可知
			num3[i + j - 1] += num1[i] * num2[j];
			if (num3[i + j - 1] > 9999) {
				//num3[i + j - 1] 逢万进位
				num3[i + j] += num3[i + j - 1] / 10000;
				num3[i + j - 1] %= 10000;
			}
		}
	}
	//2、检查num3是否有进位,注意长度为m、n位的两个数相乘结果长度不会超过 m + n
	//初始化num3的长度为 num1、num2之和
	num3[0] = num1[0] + num2[0];
	for (int i = 1; i < num3[0]; ++i) {
		if (num3[i] > 10000) {
			num3[i + 1] += num3[i] / 10000;
			num3[i] %= 10000;
		}
	}
	//如果最高位为0,说明结果小于
	if (num3[num3[0]] == 0) {
		num3[0] -= 1;
	}
}

//将数字字符串转成int数组,比如"12304560001",转换结果为[3, 1, 456, 123]
void strToInts(string num, int* numInts, int maxLen) {
	memset(numInts, 0, maxLen);
	for (int i = (int)num.size() - 1; i >= 0; ) {
		int tempNum = 0, j = 0, weight = 1;
		//取出四位转成整形
		while (i >= 0 && j++ < 4) {
			tempNum +=  (num[i--] - '0') * weight;
			weight *= 10;
		}
		numInts[++numInts[0]] = tempNum;
	}
}

//将int数组转换会字符串类型
string intsToStr(int* numInts) {
	if (numInts[0] == 0) {
		return  "0";
	}
	//最高位不需要补零
	string resStr = to_string(numInts[numInts[0]]);
	//注意访问顺序,是从高->低
	for (int i = numInts[0] - 1; i >= 1; --i) {
		string tempStr = "";
		//中间不足四位需要补零
		if (numInts[i] < 1000) {
			tempStr += '0';
		}
		if (numInts[i] < 100) {
			tempStr += '0';
		}
		if (numInts[i] < 10) {
			tempStr += '0';
		}
		tempStr += to_string(numInts[i]);
		resStr.append(tempStr);
	}
	return resStr;
}

string mutli(string num1, string num2) {
	int intsNum1[101] = { 0 }, intsNum2[101] = { 0 }, intsSum[101] = { 0 };
	strToInts(num1, intsNum1, 101);
	strToInts(num2, intsNum2, 101);
	bigNumMutli(intsNum1, intsNum2, intsSum, 101);
	return intsToStr(intsSum);
}

int main() {
	string a, b;
	//scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1
	while (cin >> a >> b) {
		string tempRes = mutli(a, b);
		if ((a[a.size() - 1] - '0') % 2 == 0 || (b[b.size() - 1] - '0') % 2 == 0) {
			tempRes += ".00";
		} else {
			//注意:√2 - 1 = 0.41
			tempRes += ".41";
		}
		cout << tempRes << endl;
	}
	return 0;
}

在这里插入图片描述

更多大数计算,请参考我的博客:

C++自封装工具类 大数计算器(万进制实现)

发布了1008 篇原创文章 · 获赞 272 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/104706905