题目
每个正数都可以用指数形式表示。
例如,137=27+23+20。
让我们用 a(b) 来表示 ab。
那么 137 可以表示为 2(7)+2(3)+2(0)。
因为 7=2(2)+2+2(0),3=2+2(0),所以 137 最终可以表示为 2(2(2)+2+2(0))+2(2+2(0))+2(0)。
给定一个正数 n ,请你将 n 表示为只包含 0 和 2 的指数形式。
输入格式
输入包含多组数据。
每组数据占一行,一个正数 n。
输出格式
每组数据输出一行,一个指数形式表示。
数据范围
1≤n≤20000 每个输入最多包含 100 组数据。
输入样例:
1315
输出样例:
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)
思路和代码
这道题用递归来写。
递归这个东西刚刚接触的时候会觉得有点难想,但是想通了就很好写,会写的很爽。
我稍微分享下我分析递归的心得吧:
- 假设这个递归你已经写完了,能直接用。
- 分析问题,看怎么拆分成子问题
- 找到特殊的结束递归点
这不是废话吗
思路
递归的函数要干什么?
假设递归写完的前提是你得知道你写的函数是做什么的。对这道题直接就是题目问的东西了:
输入一个数,输出其只包含0, 2的指数形式。
这样我们就直接假设我们已经实现这个功能了,我们来具体看看怎么拆分成子问题。
拆分子问题
题目提示了。137拆分为137=27+23+20。那很明显子问题就是把7,3,0再递归下。
电脑都是二进制存的,用二进制看题目的拆分的话非常简单,就是哪个位置上有1才分的结果就有2的某位次方。因此只要不断右移再与1就能拆分提取了,如:
stack<int> s;
int count = 0;
while (n) {
if (n & 1) s.push(count);
n >>= 1;
count++;
}
这里使用栈是注意到题目输出的顺序是按幂大到小的,而我是按小到大来拆这个数的。栈能直接实现逆序。
拆分之后就是输出了。这里的格式有些麻烦:
当拆分出来的是2的1次幂,就是2时,要直接输出2
所以能写出如下的代码:
while (!s.empty()) {
cout << "2";
if (s.top() == 1) { // 2的1次幂
cout << (s.size() == 1 ? "" : "+"); // 判断要不要“+”,下同
}
else {
cout << "(";
summon(s.top()); // 调用递归
cout << (s.size() == 1 ? ")" : ")+");
}
s.pop();
}
结束递归的条件?
这更简单不过了,题目要求所有的数都用0或2表示,那特殊的点肯定就是这两个了。
-
输入2 直接输出2
-
输入0 直接输出0
这个代码就不单独放上来了。
那么这题就写完了
代码
// https://www.acwing.com/problem/content/description/3486/
#include<bits/stdc++.h>
using namespace std;
void summon(int n) {
if (n==0) {
cout << "0";
return;
}
if (n==2) {
cout << "2";
return;
}
stack<int> s;
int count = 0;
while (n) {
if (n & 1) s.push(count);
n >>= 1;
count++;
}
while (!s.empty()) {
cout << "2";
if (s.top() == 1) {
cout << (s.size() == 1 ? "" : "+");
}
else {
cout << "(";
summon(s.top());
cout << (s.size() == 1 ? ")" : ")+");
}
s.pop();
}
}
int main() {
int n;
while (cin >> n) {
summon(n);
cout << endl;
}
return 0;
}