题目大意,循环读入一个1~1000的数字n,你现在只有一个数x,你的任务是输出得到x^n需要的最小步数,你可以使用当前循环里得到的任意数,题里的x^31,可以通过如下步骤
1. x*x->x^2
2.x^2 * x^2 ->x^4
3.x^4 * x^4 ->x^8
4.x^8 * x^8 ->x^16
5.x^16 * x^16 ->x^32
6.x^32 /x ->x^31
然后我懵逼四十分钟,乱搞十分钟,IDA*水过
我们不难发现,x^n与x无关,所以我们只需要看n,于是我们可以发现,x^a1*x^a2=x^(a1+a2),x^a1/x^a2=x^(a1-a2),我们完全不需要乘乘除除,只需要加减即可,模拟用最少的加减次数达到n
用一个ans数组,存储第i步时,达到的和,IDA*时,当前deepth+1在ans中的值可以是ans[deepth]+ans[1~deepth],相当于模拟x^deepth*x^(1~deepth),也可以是ans[deepth]-ans[1~deepth],相当于模拟x^deepth / x^(1~deepth),如果当前IDA*的deepth在ans中的值==n,return 1;
剪枝,如果当前搜索到的deepth在ans中的值的limit次方(当前递归的限制深度)都达不到n,那么就直接return 0,因为就算当前递归的最大值就是ans[deepth]^limlit,他都小于n,那么ans[deepth]加上deepth小于当前深度的deepth在ans中的值永远不可能达到n,显然对吧,ok,看代码
By Acer.Mo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int x;
int lim;
int ans[5000];
int IDAS(int limdep)
{
if (limdep>lim) return 0;
if ((ans[limdep]<<lim-limdep)<x) return 0;//剪枝
if (ans[limdep]==x) return 1;
for (int i=0;i<=limdep;i++)
{
ans[limdep+1]=ans[limdep]+ans[i];
if (IDAS(limdep+1)) return 1;//乘方
ans[limdep+1]=ans[limdep]-ans[i];
if (IDAS(limdep+1)) return 1;//除
}
return 0;
}
int main()
{
ans[0]=1;
while (~scanf("%d",&x)&&x)
{
for (lim=0;;lim++)
if (IDAS(0)) break;
printf("%d\n",lim);
}
return 0;
}