火柴棒等式
此题有两种以上的解法,这里简单阐述一下回溯的解法,也是本题想要考察的知识点。
题目分析:由于该题目中规定了n ≤ \leq ≤ 25,由于1111+1=1112已经用掉了8+2+2+2+11=25根火柴棒,所以该题中可能出现的最大的数只有1000多,所以定义数组的时候数组的大小可以开到2000
回溯法代码:
#include <bits/stdc++.h>
using namespace std;
int a[2005]={6,2,5,5,4,5,6,3,7,6},b[4];
//a[n]数组存放数字n所需要的火柴棒的个数,b[n]存放等式中从左往右的的数字
int n;//火柴棒的个数
int cnt;//存放结果
void mySearch(int k){
for(int i=0;i<=2000;i++){
if(n-a[i] >= 0){//1.如果还满足火柴棒足够这个条件,进行相关数据的更新
b[k]=i;//等式中第k个数为i
n=n-a[i];//减去所需要的火柴棒的个数
if(k == 3){//2.是否满足该回溯分支的结束条件
//2.1是否满足题意要求
if(b[1]+b[2]==b[3] && n==0) cnt++;
}else{
//不符合回溯分支结束的条件,无脑回溯该分支的下一阶段(暴力回溯)
mySearch(k+1);
}
n=n+a[i];//3.处理完该回溯的分支,还原现场
}
}
}
int main()
{
cin>>n;
n=n-4;//此处-4是减去+和=所用的火柴棒
//数组的初始化
for(int i=10;i<=2000;i++){
a[i]=a[i%10]+a[i/10];
}//计算出二位三位四位数字所需要的火柴棒个数,这里跟递归的思想有点像,后面的数组的计算用到了前面已经计算过的数组(自己调用自己)
//也可以用以下常规的方式对数组进行初始化(一位一位的相加)
/*
for(int i=1;i<=2000;i++){
k=i;temp=0;
while(k){
temp+=a[k%10];
k/=10;
}
a[i]=temp;
}
*/
mySearch(1);
cout<<cnt;
return 0;
}
由于该回溯没有对回溯进行分支限界,所以该回溯算法是最基本的回溯法,属于回溯暴力搜索
该题目还有另一个简单的解法
#include <bits/stdc++.h>
using namespace std;
int a[2005]={6,2,5,5,4,5,6,3,7,6};
int n,cnt;
int main()
{
cin>>n;
for(int i=10;i<=2000;i++){
a[i]=a[i%10]+a[i/10];
}
for(int i=0;i<=999;i++){
for(int j=0;j<=999;j++){
if(a[i]+a[j]+4+a[i+j]==n){
ans++;
}
}
}
cout<<cnt;
return 0;
}
同样是对所有可能的情况进行遍历,可能就属于循环结构中比较简单的一道题。
但是! 我做这个题真正的目的不是复习回溯,也不是熟悉循环结构,而是学习打表!由于该题目的数据较小,n
≤
\leq
≤ 25,最适合打表辣。
我们把上面分支结构的代码进行修改:
#include <bits/stdc++.h>
using namespace std;
int a[2005]={6,2,5,5,4,5,6,3,7,6};
int n=1,cnt;
int main()
{
for(int i=10;i<=2000;i++){
a[i]=a[i%10]+a[i/10];
}
while(n<=25){
cnt=0;
for(int i=0;i<=999;i++){
for(int j=0;j<=999;j++){
if(a[i]+a[j]+4+a[i+j]==n){
cnt++;
}
}
}
cout<<cnt<<" ";
n++;
}
return 0;
}
输出结果:0 0 0 0 0 0 0 0 0 0 0 0 1 2 8 9 6 9 29 39 38 65 88 128 192
下一步,开数组,记录结果
#include <bits/stdc++.h>
using namespace std;
int a[30]={0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,2 ,8 ,9 ,6 ,9 ,29, 39, 38, 65, 88, 128, 192};
int main()
{
int n;
cin>>n;
cout<<a[n-1];
return 0;
}
过啦!因为一个月后就要比赛了,我比较功利性。。。根据蓝桥杯比赛的机制,打表肯定是要学的。。。各位大佬不要骂我。。。