PAT (Advanced Level) 1010 Radix (25 分)

版权声明:转载请附链接 https://blog.csdn.net/isunLt/article/details/83997147

1010 Radix (25 分)

Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The answer is yes, if 6 is a decimal number and 110 is a binary number.
Now for any pair of positive integers N​1​​ and N​2​​, your task is to find the radix of one number while that of the other is given.

Input Specification:

Each input file contains one test case. Each case occupies a line which contains 4 positive integers:
N1 N2 tag radix
Here N1 and N2 each has no more than 10 digits. A digit is less than its radix and is chosen from the set { 0-9, a-z } where 0-9 represent the decimal numbers 0-9, and a-z represent the decimal numbers 10-35. The last number radix is the radix of N1 if tag is 1, or of N2 if tag is 2.

Output Specification:

For each test case, print in one line the radix of the other number so that the equation N1 = N2 is true. If the equation is impossible, print Impossible. If the solution is not unique, output the smallest possible radix.

Sample Input 1:

6 110 1 10

Sample Output 1:

2

Sample Input 2:

1 ab 1 2

Sample Output 2:

Impossible

Code

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

typedef long long LL;

LL str2num(string sn, LL radix)
{
	LL curr_rad = 1;
	LL sum = 0;
	for (int i = sn.length() - 1; i >= 0; i--)
	{
		int digit;
		if (sn[i] <= '9')
			digit = sn[i] - '0';
		else if (sn[i] >= 'a' && sn[i] <= 'z')
			digit = sn[i] - 'a' + 10;
		sum += digit * curr_rad;
		curr_rad *= radix;
	}
	return sum;
}
LL find_radix(string str, long long num) {
	LL result_radix = -1;
	LL lowb, highb;
	lowb = -1;
	for (auto ch : str)
	{
		int digit;
		if (ch >= '0' && ch <= '9')
			digit = ch - '0';
		else if (ch >= 'a' && ch <= 'z')
			digit = ch - 'a' + 10;
		lowb = digit > lowb ? digit : lowb;
	}
	lowb++;
	highb = num + 1;
	while (lowb <= highb) 
	{
		LL mid = lowb + (highb - lowb) / 2;
		LL temp = str2num(str, mid);
		if (temp<0 || temp>num)
		{
			highb = mid - 1;
		}
		else if (temp < num) { lowb = mid + 1; }
		else { result_radix = mid; break; }
	} 
	return result_radix;
}

int main()
{
	LL n1, n2;
	n1 = n2 = 0;
	string sn1, sn2;
	int tag;
	LL	radix;
	cin >> sn1 >> sn2 >> tag >> radix;
	LL radixGuass;
	if (tag == 1)
	{
		n1 = str2num(sn1, radix);
		radixGuass = find_radix(sn2, n1);
	}
	else if (tag == 2)
	{
		n2 = str2num(sn2, radix);
		radixGuass = find_radix(sn1, n2);
	}
	if (radixGuass != -1)
		cout << radixGuass << endl;
	else
		cout << "Impossible" << endl;
	return 0;
}

思路

这道题有很多坑,开始我也被坑了,后来看了
https://blog.csdn.net/CV_Jason/article/details/80993283
这个大佬的解析才豁然开朗
因为指数radix理论上是可以无穷大,而不仅限于2~36(每一位0 ~ 9,a ~ z的取值范围很容易让人有radix在2 ~ 36的假设)所以即使使用long long类型的变量,也有可能产生上溢(overflow);因为计算机内部使用补码表示整数,发生上溢时,这个数会变成负数,因此在二分查找算法中,如果猜测数变成负数,就说明发生了上溢,那么,right = mid -1,这很巧妙。

		while (lowb <= highb) 
		{
			long long mid = lowb + (highb - lowb) / 2;
			long long temp = str2num(str, mid);
			if (temp<0 || temp>num)
			{
				highb = mid - 1;
			}
			else if (temp < num) { lowb = mid + 1; }
			else { result_radix = mid; break; }
		} 

这里是实现二分查找算法的部分,mid表示我们猜测的级数,所以temp是我们根据mid将输入的str转换成十进制表示的数,首先需要判断temp是否小于0,如果小于零,就说明temp太大,我们猜的mid太大,需要在左半边重新猜,如果不先判断这个,那么temp将必然小于num,算法误以为temp太小,而在右半边重新猜,导致错误,也就是说这段代码不能这么写:

		while (lowb <= highb) 
		{
			long long mid = lowb + (highb - lowb) / 2;
			long long temp = str2num(str, mid);
			if (temp < num) { lowb = mid + 1; }
			else if (temp<0 || temp>num)
			{
				highb = mid - 1;
			}
			else { result_radix = mid; break; }
		} 

关于二分查找算法
种类很多,我是参考
二分查找有几种写法?它们的区别是什么? - 胖君的回答 - 知乎
https://www.zhihu.com/question/36132386/answer/155438728
以上

猜你喜欢

转载自blog.csdn.net/isunLt/article/details/83997147