PAT甲级1010 Radix//进制转换//二分优化查找

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 N2​​ , your task is to find the radix of one number while that of the other is given.

翻译:给定一对正整数,例如6和110,这个等式6=110能成立吗?如果6是十进制数,110是二进制数,那么答案是“是”。
现在对于任何一对正整数N1和N2,你的任务是找到一个数的基数,而另一个数的基数是给定的。

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.

翻译:每个输入文件包含一个测试用例。每个案例占用一行,其中包含4个正整数:
N1 N2标记基数
这里N1和N2各不超过10位。每位数小于其基数,并且是从集合{0-9,a-z}中选择的,其中0-9代表十进制数0-9,a-z代表十进制数10-35。最后一个数radix是N1的基数,如果tag是1,则是N2的基数。

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.

翻译:对于每个测试用例,在一行中打印另一个数字的基数,以便让N1=N2为真。如果等式是不成立的,请打印“不可能”。如果解不是唯一的,则输出尽可能小的基数。

Sample Input 1:

6 110 1 10

Sample Output 1:

2

思路

题目大意是是给定两个数,寻找一个数的进制使其等于另一个数。刚开始以为只是比较普通的进制转换问题,后来发现这题目考的更深。这题也让我对进制有了进一步的理解。这里也将讲述每次提交的代码的思路。

第一次20分做法

刚开始以为题目不算难,就用了比较普通的方法,但是后来发现漏洞百出。具体思路是写两个函数change()和judge()。其中change()用来计算不同进制下的数对应的十进制数是多少方便后来判断;judge()用来判断不同进制下两个数是否能相等。

#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
int change(string, int);
int judge(string, int);
int main()
{
	string n1, n2;
	int tag, radix;
	cin >> n1 >> n2 >> tag >> radix;
	switch(tag)
	{
	case 1:
		{
			int d = judge(n2, change(n1, radix));
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	case 2:
		{
			int d = judge(n1, change(n2, radix));
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
//算出该数的十进制数是多少
int change(string s, int n)
{
	int ans = 0, r = 0;
	for (int i = s.size() - 1; i >= 0; i--)
	{
		if (s[i] >= '0' && s[i] <= '9')
			ans = ans + (s[i] - '0') * pow((float)n, r);
		else
			ans = ans + (s[i] - 'a' + 10) * pow((float)n, r);
		r++;
	}
	return ans;
}
//用来判断不同进制下两个数是否能相等
int judge(string ss, int nn)
{
	for (int radix = 2; radix <= nn; radix++)
	{
		int num = change(ss, radix);
		if (num == nn)
			return radix;
	}
	return 0;
}

可以发现judge()函数里第二个for循环radix默认就直接从2开始了,这是错误的。如果ss是5,就会调用函数change(5, 2)来算二进制下5的值是多少,而且change(5, 2)还真能返回5!可是二进制里根本不会出现5这个数啊!所以这个for循环肯定不是默认从2开始,对于不同的数其进制肯定有不同的下界

第二次24分做法

通过看1010 Radix (25 分)这一题解之后知道了如何找出下界。现在假设输入两个数N1、N2,标记tag、基数radix,tag为1。基数的最小值就是N2中最大的一位数+1,为什么呢?假设N2是112,其中2是最大的,则这个数至少是三进制的,如果是二进制就不可能出现2;假设N2是abab,则这个数至少也是十二进制的,理由同上。

接着找出上界。当N2有两位或以上时,十位最小也得是1,如果基数是N1,这个数就必然会大于等于N1,所以再大就没有必要比较了。这样似乎可以得到上界是N1?我们先改一下代码,写一个getMaxRadix()来求得N2中最大的那一位,然后改变judge()中的下界上界

int getMaxRadix(string s)
{
	char max = '0';
	for (int i = 0; i < s.size(); i++)
		if (s[i] > max)
			max = s[i];
	if (max >= '0' && max <= '9')
		return max - '0' + 1;
	else
		return max - 'a' + 11;
}
int judge(string ss, int nn)
{
	int maxn = getMaxRadix(ss);
	for (int radix = maxn; radix <= nn; radix++)
	{
		int num = change(ss, radix);
		if (num == nn)
			return radix;
	}
	return 0;
}

改的没错,但是这时候如果输入5 5 1 10计算机就会输出Impossible。实际上六进制的话是完全没问题的。这就是我们疏忽的一个坑点,如果N1和N2相同会发生什么?就按照上面的例子来看,此时下界是6,上界却是5,因为不满足循环条件所以直接return 0,最后输出Impossible。因为这种特殊状况的存在我们上界就应该改成N1 + 1。同时注意一点最好用long long类型来存储数据
更改后的代码:

#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
long long change(string, long long);
long long judge(string, long long);
int getMaxRadix(string);
int main()
{
	string n1, n2;
	int tag;
	long long radix;
	cin >> n1 >> n2 >> tag >> radix;
	switch(tag)
	{
	case 1:
		{
			int d = judge(n2, change(n1, radix));
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	case 2:
		{
			int d = judge(n1, change(n2, radix));
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
long long change(string s, long long n)
{
	long long ans = 0;
	int r = 0;
	for (int i = s.size() - 1; i >= 0; i--)
	{
		if (s[i] >= '0' && s[i] <= '9')
			ans = ans + (s[i] - '0') * pow((double)n, r++);
		else
			ans = ans + (s[i] - 'a' + 10) * pow((double)n, r++);
	}
	return ans;
}
long long judge(string ss, long long nn)
{
	int maxn = getMaxRadix(ss);
	for (int radix = maxn; radix <= nn + 1; radix++)
	{
		long long num = change(ss, radix);
		if (num == nn)
			return radix;
	}
	return 0;
}
int getMaxRadix(string s)
{
	char max = '0';
	for (int i = 0; i < s.size(); i++)
		if (s[i] > max)
			max = s[i];
	if (max >= '0' && max <= '9')
		return max - '0' + 1;
	else
		return max - 'a' + 11;
}

此时只差测试点7没有ac了,测试点7提示超时,所以我们还应该优化一下,这里选择用二分法优化寻找进制的过程

#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
long long change(string, long long);
long long judge(string, long long, long long, long long);
int getMaxRadix(string);
int main()
{
	string n1, n2;
	int tag;
	long long radix;
	cin >> n1 >> n2 >> tag >> radix;
	switch(tag)
	{
	case 1:
		{
			long long n =change(n1, radix);
			long long d = judge(n2, n, getMaxRadix(n2), n + 1);
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	case 2:
		{
			long long n = change(n2, radix);
			long long d = judge(n1, n, getMaxRadix(n1), n + 1);
			if (d)
				cout << d << endl;
			else
				cout << "Impossible" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
long long change(string s, long long n)
{
	long long ans = 0;
	int r = 0;
	for (int i = s.size() - 1; i >= 0; i--)
	{
		if (s[i] >= '0' && s[i] <= '9')
			ans = ans + (s[i] - '0') * pow((double)n, r++);
		else
			ans = ans + (s[i] - 'a' + 10) * pow((double)n, r++);
	}
	return ans;
}
long long judge(string ss, long long nn, long long start, long long end)
{
	if (start == end)
	{
		if (change(ss, start) == nn)
			return start;
		else
			return 0;
	}
	else if (start < end)
	{
		long long radix = (start + end) / 2;
		long long ans = change(ss, radix);
		if (ans == nn)
			return radix;
		else if (ans > nn || ans < 0)
			return judge(ss, nn, start, radix);
		else
			return judge(ss, nn, radix + 1, end);
	}
	return 0;
}
int getMaxRadix(string s)
{
	char max = '0';
	for (int i = 0; i < s.size(); i++)
		if (s[i] > max)
			max = s[i];
	if (max >= '0' && max <= '9')
		return max - '0' + 1;
	else
		return max - 'a' + 11;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值