我得到的数字N <= 200,我只需要使用此算法找到palindrom,然后输出palindrom和迭代次数:
1)逆向
2)撤消号码+上一个
示例:
1)N = 99
出99 0
2)N = 69
69 + 96 = 165 165 + 561 = 726 726 + 627 = 1353 1353 + 3531 = 4884
出场:4884 4
我的代码:
#include <iostream>
using namespace std;
int rev(int a)
{
int b = 0;
while (a)
{
b = 10 * b + a % 10;
a /= 10;
}
return b;
}
int main()
{
ios::sync_with_stdio(0);
int n, c = 0;
cin >> n;
while (n != rev(n))
{
n = n + rev(n);
c++;
}
cout << n << endl << c;
return 0;
}
它仅适用于100个测试中的70个:(
您能帮助我,使其适用于所有测试吗?
答案 0 :(得分:1)
这仅仅是整数溢出的问题。第一个实现是用unsigned long long实现的。它似乎可以正常工作,但未检测到一些溢出。
使用__int128执行了新的实现。此外,使用了签名版本,以便能够轻松检测溢出。
现在,对于介于1和200之间的n,找到所有回文,但n = 196除外,这是检测到溢出的原因。
这是程序:
#include <iostream>
//using namespace std;
void print128 (__int128 a) {
__int128 v64 = (__int128) 1 << 64;
__int128 high128 = a / v64;
__int128 low128 = a % v64;
unsigned long long high = high128;
unsigned long long low = low128;
if (high > 0) std::cout << high;
std::cout << low;
}
__int128 rev(__int128 a) {
__int128 b = 0;
while (a) {
b = 10 * b + a % 10;
a /= 10;
}
return b;
}
int main() {
//std::ios::sync_with_stdio(0);
int nerr = 0;
int cmax = 100000;
for (int n0 = 10; n0 <= 200; n0++) {
bool overf = false;
int c = 0;
__int128 nrev;
__int128 n = n0;
while ((n != (nrev = rev(n))) && (c < cmax)) {
if (nrev < 0) overf = true;
n = n + nrev;
if (n < 0) overf = true;
c++;
}
std::cout << "n = " << n0 << " ";;
if ((c == cmax) && !overf) {
std::cout << " ERR0R\n";
nerr++;
} else if (overf) {
std::cout << " OVERFLOW\n";
nerr++;
} else {
std::cout << " palym = ";
print128 (n);
std::cout << " c = " << c << "\n";
}
}
std::cout << "Nbre of errors = " << nerr << "\n";
return 0;
}
问题是“对196案该怎么办?”我们不知道是否存在解决方案,即是否存在收敛。而且,如果收敛,我们将不知道回文的大小。尝试将int
与更多的位一起使用可能是一场漫长的竞赛。更好的方法是实现一个适合于该问题的专用int类型,即一个int向量,每个int在0到9之间。对于该算法,我们只有两个操作要执行,计算回文和加法。计算回文将是微不足道的,将向量的元素求逆(忽略第一个零),并且加法将很容易实现。而且,这样的添加将容易检测溢出。最后但并非最不重要的是,向量的大小可能适用于每个n
值,直到给定限制为止。
编辑:在评论中,马克·兰瑟姆(Mark Ransom)提供了有关Lychrel数字的Wikipedia页面的链接,该数字即算法将不会收敛的数字。最低和最著名的“候选人Lychrel”编号196是。据推测,没有证明196是这样的数字。实验一直进行到数十亿个数字为止,但没有找到这个数字的收敛性。