问题描述:
任何一个正整数都可以用2的幂次表示,例如137=2 7+ 2 3 + 2 0 ,同时约定用括号来表示,即ab可表
示为a(b)。
由此可知,137可表示为2(7)+2(3)+2(0),进一步,7=22+2+20(21用2表示),3=2+20,所以
最后137可表示为2(2(2)+2+2(0))+2(2+2(0))+2(0)。
又如,1315表示为2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0);
输入格式: (一行一个正整数n,n<=20000)
137
输出格式
2(2(2)+2+2(0))+2(2+2(0))+2(0)。
问题分析:
方法一:将n拆分为若干2的幂次方的和,再将各个幂次方(指数)拆分成为若干2的幂次的和……这是递归的思想。递归的边界是什么呢?指数 n=0时候 直接输出2(0),n=1的时候输出 2。如果n>1的时候 那么应该直接输出“2(“,再对指数进行递归,递归后补上括号“)”(类似回溯恢复现场) 整个递归的过程类似于深度优先搜索(DFS)。+号的处理是本题的难点 ,什么时候输出 ‘+’号呢,如果X- 2n不为0,那么说明他剩余部分也需要进行分解的,所以应该需要输出‘+’,例如 137-27=9 那么说明分解了7后 一定要有+号,才能把9部分的分解也加上。
#include<bits/stdc++.h>
using namespace std;
int x,a[32];
void npow(int n){
for(int i=x;i>=0;--i){
if(a[i]<=n){
n=n-a[i];
if(i>1){
cout<<"2(";
npow(i); //可以理解为DFS搜索
cout<<")"; //回溯
}
if(i==1) cout<<"2";
if(i==0) cout<<"2(0)";
if(n!=0) cout<<"+"; //若此n还没分解完,则后面还有项,所以输出一个+号
}
}
}
int main()
{
int n;
cin>>n;
a[0]=1;
while(a[x]<n){
x++;
a[x]=a[x-1]*2;
}
npow(n);
cout<<endl;
return 0;
}
方法二:分治的思想,把一个数X分解为 pow(2,log2(X)) 和 X- pow(2,log2(X))进行递归求解,这样可以简单的处理好“+”号的问题。
#include<bits/stdc++.h>
using namespace std;
string f(int x){
if (x==1) return "2(0)";
if (x==2) return "2";
if (x==3) return "2+2(0)"; //防止3 输出2(2(0))+2(0);
int n=log2(x); // 求出指数取整
int t=pow(2, n);
if (x==t) return "2("+f(n)+")"; // x 恰好是 2的n次放,后面就没有了 不需要+号。
else return "2("+f(n)+")+"+f(x-t); //不是2的n次方,那么对2部分分别进行递归求解用+号连接
}
int main(){
int x;
cin>>x;
cout<<f(x)<<endl;
}
方法三:打表法(作弊)
因为题目中数据规模是20000 <215 ,所以如果 我们把指数0-14 的表示好放在一个字符串数组里面,如果来了一个数X,我们只需要把对应的幂次方直接输出即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
string s[16]={"2(0)","2","2(2)","2(2+2(0))","2(2(2))","2(2(2)+2(0))","2(2(2)+2)",
"2(2(2)+2+2(0))","2(2(2+2(0)))","2(2(2+2(0))+2(0))","2(2(2+2(0))+2)",
"2(2(2+2(0))+2+2(0))","2(2(2+2(0))+2(2))","2(2(2+2(0))+2(2)+2(0))",
"2(2(2+2(0))+2(2)+2)","2(2(2+2(0))+2(2)+2+2(0))"};
bool temp=0;
for(int i=15;i>=0;i--)
if(pow(2,i)<=n)
{
n-=pow(2,i);
if(temp)
cout<<'+';
cout<<s[i];
temp=1;
}
return 0;
}