火柴棒等式——回溯搜索

火柴棒等式
此题有两种以上的解法,这里简单阐述一下回溯的解法,也是本题想要考察的知识点。


题目分析:由于该题目中规定了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;
}

过啦!因为一个月后就要比赛了,我比较功利性。。。根据蓝桥杯比赛的机制,打表肯定是要学的。。。各位大佬不要骂我。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值