題目
https://www.patest.cn/contests/pat-a-practise/1024
已知非迴文串可以通過不斷和自身逆序相加來得到迴文串,稱爲一次操作,如67+76=143+341=484的操作次數爲2。給定一個正數N和操作的最大次數,判斷該數串在最大操作次數內能否得到迴文串。
解題思路
由於N最大可以爲10^10,操作次數最多可以爲100次,所以數字長度會很長,在long long int內會溢出,所以必須要用大整數相加。
用二維數組num存放每一次操作得到的數字(num[0]爲輸入的原始數字)一維數組row_cnt記錄num每一行的數字有效長度。第step次運算前先判斷是否已經得到迴文串,若已經得到則跳出循環,否則取num[step-1]這一行的數字進行逆序相加和判斷進位,存放到num[step]這一行,更新row_cnt[step]。
第一次交的時候測試點6和8都沒有通過,仔細檢查了代碼是沒有問題的,後來看了大神博客才知道是二維數組的列寬太小了,20和50都不夠,100才能全部通過。(有可能每次都要溢出進位,所以今後要想清楚了再聲明啊!)
自己的方法太複雜了,https://www.liuchuo.net/archives/2329這篇博客裏用STL的string和reverse來快速解題。真是高下立見。
STL的方法如下:
判斷迴文串只需reverse當前字符串s得到t,用s==t來判斷是否迴文。
計算時也只需要將t逐位加到s上,判斷進位,(正着加和反着加是沒有區別的,爲自己智商捉急),最後將s逆序即得到這一次操作後的結果。
AC代碼
複雜的二維數組法
#include <iostream>
#include <cstring>
using namespace std;
int num[110][100]; //存放每一步的運算結果
int row_cnt[110] = {0}; //num矩陣每行的有效數字長度
void print(int row) //輸出第row行數字
{
for (int j = row_cnt[row] - 1; j >= 0; --j)
cout << num[row][j];
cout << endl;
}
bool isPalindromic(int row) //判斷第row行是不是迴文數字
{
bool flag = true;
int maxj = row_cnt[row];
for (int j = 0; j <= maxj/2; ++j) //判斷迴文串
{
if (num[row][j] != num[row][maxj-1-j])
{
flag = false;
break;
}
}
return flag;
}
int main()
{
memset(num, 0, sizeof(num));
int limit;
char str[20];
cin >> str >> limit;
int j = 0;
for (int i = strlen(str)-1; i >= 0; --i)
num[0][j++] = str[i] - '0';
row_cnt[0] = j;
int step = 0;
while(step < limit)
{
bool check = isPalindromic(step);
if (check)
{
print(step);
cout << step << endl;
return 0;
}
step += 1;
int last = row_cnt[step-1]; //last爲上一行的數字長度
for (int j = 0; j < last; ++j) //逆序相加
{
num[step][j] += num[step-1][j] + num[step-1][last-1-j];
num[step][j+1] = num[step][j] / 10;
num[step][j] %= 10;
}
row_cnt[step] = (num[step][last] == 0)?last:last+1;
}
print(step);
cout << limit << endl;
return 0;
}
簡練的STL大法:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string s;
void add()
{
string t = s;
reverse(t.begin(), t.end());
int len = s.length(), carry = 0;
for (int i = 0; i<len; ++i) //將t各位累加到s上
{
s[i] = s[i] + t[i] + carry - '0'; //注意s是字符串
if (s[i] > '9') //要用字符'9'判斷進位
{
s[i] = s[i] - 10;
carry = 1;
}
else carry = 0;
}
if (carry == 1) s += '1'; //溢出進位
reverse(s.begin(), s.end());
}
int main()
{
int limit;
cin >> s >> limit;
int step = 0;
while (step < limit)
{
string t = s;
reverse(t.begin(), t.end());
if (s == t) //判斷迴文
{
cout << s << endl << step;
return 0;
}
step += 1;
add();
}
cout << s << endl << step;
return 0;
}