22-小学生的数学题目?exm?

一、具体描述

寒假作业

现在小学的数学题目也不是那么好玩的。 
看看这个寒假作业:

□ + □ = □ 
□ - □ = □ 
□ × □ = □ 
□ ÷ □ = □

(如果显示不出来,可以参见【图1.jpg】)

每个方块代表1~13中的某一个数字,但不能重复。 
比如: 
6 + 7 = 13 
9 - 8 = 1 
3 * 4 = 12 
10 / 2 = 5

以及:  
7 + 6 = 13 
9 - 8 = 1 
3 * 4 = 12 
10 / 2 = 5

就算两种解法。(加法,乘法交换律后算不同的方案)

你一共找到了多少种方案?

可以用深度优先遍历和暴力破解。

**暴力思路**

更详细地讲,为方便说明,具体假设及思路流程如下:

a1+a2=x1;

a3-a4=x2;

a5*a6=x3;

a7/a8=x4;

a1,a2,a3...a8;x1,x2,x3,x4的范围为[1,13],且均为整数,有且仅出现过一次。

我们想用暴力,那么就得尽可能的降低时间复杂度以达到最佳效果。既然这样,我们发现,x1,x2,x3,x4是受到a1,a2...a8这8个数影响的,所以我们只需要遍历8个数即可。对于x1,x2,x3,x4,我们可以根据8个数的值来确定是否存在。

那么什么是存在问题呢?其实等同可以说符合问题,我们一旦确认一个数的值(比如确定第一个数a1),就将它标记一次,以说明它不能在后续遍历(比如遍历a2等)的时候用到了。那么,我们开始遍历吧。

1. 确定a1。

标记 vis[a1]=1 。

2. 确定a2。

(1) 判断 a1+a2>13 ? (如果>13,即x1>13,遍历下一个a2) 并且 vis[a2]==1 ? (如果已经标记了a2,遍历下一个a2)。

(2) 如果不符合(1),则说明a2是可能符合的,继续标记 vis[a2]=1,vis[a1+a2]=1(vis[x1]=1),即这时的a1,a2,x1均被标记了,下面就不能再出现了。

3. 确定a3。

只要判断 a3 是否被标记即可( vis[a3]==1 ? ),如果没有,记下a3( vis[a3]=1),继续遍历下面的数。

4. 确定a4。

(1) a3-a4<0 ? a3-a4必须大于0。

(2) a3-a4>14 ? a3-a4必须小于14。

(3) vis[a4]==1 ? vis[a3-a4]==1 (vis[x2]==1)? 我们当然知道,这是不能被标记的。

(4) 这是最重要的一点,一定要确定 a3-a4 是否等于 a4;因为如果(1)(2)(3)均不符合,就说明a4还没有被标记;如果 a3-a4继续等于a4,那么这个条件被隐性符合了,然而这是不对的!

(5) 如果(1)(2)(3)(4)均不符合,那么我们可以标记vis[a4]=1,vis[a3-a4]=1(vis[x2]=1)了。

5. 确定a5。

只要判断 a5 是否被标记即可( vis[a5]==1 ? ),如果没有,记下a5( vis[a5]=1),继续遍历下面的数。

6. 确定a6。

(1) a5*a6 > 13 ?

(2) vis[a6]==1 ? vis[a5*a6]==1(vis[x3]==1) ?

(3) 重要的一点,同4(4),a6==a5*a6 ?

(4) 如果(1)(2)(3)均不符合,那么我们可以标记vis[a6]=1,vis[a5*a6]=1(vis[x3]=1)了。

7. 确定a7。

只要判断 a7 是否被标记即可( vis[a7]==1 ? ),如果没有,记下a5( vis[a7]=1),继续遍历下面的数。

8. 确定a8。

(1) a7<a8 ? 如果符合,那么x4不为整数。

(2) a7%a8 != 0 ? 这句话说明a7一定要整除a8。

(3) vis[a8]==1 ? vis[a7/a8]==1(vis[x4]==1) ?

(4) 重要的一点,同4(4),6(3),a8==a7/a8 ?

(5) 如果(1)(2)(3)(4)均不符合,那么不用标记a8,我们可以记录生成一种情况了。

!!!注意找到一种答案后,需要去除标记,以达到循环,否则会漏很多解,甚至无解!

**DFS思路**

按部就班,和暴力差不多。

二、代码解析

(暴力)

//
//  main.cpp
//  xiaoxuesheng
//
//  Created by apple on 2018/2/28.
//  Copyright © 2018年 apple. All rights reserved.
//
#include <iostream>
using namespace std;
int main(){
    //define
    int a1, a2, a3, a4, a5, a6, a7, a8;//representative parameters
    int vis[14] = {0};//if tag?
    int tot = 0;//record the number of the proper approaches.
    //violence
    //a1
    for (a1 = 1; a1 <= 13; ++a1) {
        vis[a1] = 1;//tag
        //a2
        for (a2 = 1; a2 <= 13; ++a2) {//----------------->a1+a2=?
            //Judge if a1+a2>13 ? yes,pass a2,continue
            if (a1 + a2 > 13 || vis[a2]) {
                continue;
            }
            //if not,tag vis[a1+a2]
            vis[a2] = 1;
            vis[a1 + a2] = 1;
            //a3,is the same as a1
            for (a3 = 1; a3 <= 13; ++a3) {
                //if taged,continue
                if (vis[a3]) {
                    continue;
                }
                //if not,tag
                vis[a3] = 1;
                //a4
                for (a4 = 1; a4 <= 13; ++a4) {//------------------->a3-a4=?
                    //Judge if yes,continue
                    if (a3 - a4 < 0 || a3 - a4 > 14 || vis[a4] || vis[a3 - a4] || a4 == a3 - a4) {
                        continue;
                    }
                    //if not,tag,the same as a1+a2
                    vis[a4] = 1;
                    vis[a3 - a4] = 1;
                    //a5,the same as a1 and a3
                    for (a5 = 1; a5 <= 13; ++a5) {
                        //if taged,continue
                        if (vis[a5]) {
                            continue;
                        }
                        //if not,tag
                        vis[a5] = 1;
                        //a6
                        for (a6 = 1; a6 <= 13; ++a6) {//------------>a5*a6=?
                            //Judge,if yes,continue
                            if (a5 * a6 > 13 || vis[a6] || vis[a5 * a6] || a6 == a5 * a6) {
                                continue;
                            }
                            //if not,tag
                            vis[a6] = 1;
                            vis[a5 * a6] = 1;
                            //a7,the same as a1,a3,a5
                            for (a7 = 1; a7 <= 13; ++a7) {
                                if (vis[a7]) {
                                    continue;
                                }
                                //if not taged,tag
                                vis[a7] = 1;
                                //a8
                                for (a8 = 1; a8 <= 13; ++a8) {//------------->a7/a8=?
                                    //Judge,if yes,continue
                                    if (vis[a8] || a7 < a8 || a7 % a8 != 0 || vis[a7 / a8] || a8 == a7 / a8) {
                                        continue;
                                    }
                                    //if not ,tot+1
                                    tot++;
                                }
                                //reduction
                                vis[a7] = 0;
                            }
                            //reduction
                            vis[a6] = 0;
                            vis[a5 * a6] = 0;
                        }
                        //reduction
                        vis[a5] = 0;
                    }
                    //reduction
                    vis[a4] = 0;
                    vis[a3 - a4] = 0;
                }
                //reduction
                vis[a3] = 0;
            }
            //reduction
            vis[a2] = 0;
            vis[a1 + a2] = 0;
        }
        //reduction
        vis[a1] = 0;
    }
    cout<<tot<<endl;
    return 0;
}

(深度优先遍历呢?)

这里先只给代码。基本思路差不多。

#include <stdio.h>
#define _MAX 13

int ans = 0;
int num[_MAX] = {0};
int visited[_MAX] = {0};

int test(int n)
{
    if (n == 2)
    {
        if (num[0] + num[1] == num[2])
        {
            return 1;
        }
    }
    else if (n == 5)
    {
        if (num[3] - num[4] == num[5])
        {
            return 1;
        }
    }
    else if (n == 8)
    {
        if (num[6] * num[7] == num[8])
        {
            return 1;
        }
    }
    else if (n == 11)
    {
        if (num[10] * num[11] == num[9])
        {
            ans++;
            return 1;
        }
    }
    else
    {
        return 1;
    }
    return 0;
}

void dfs(int n)
{
    int i = 0;
    if (n >= _MAX)
    {
        return ;
    }
    for (; i < _MAX; i++)
    {
        if (!visited[i])
        {
            visited[i] = 1;
            num[n] = i + 1;
            if (!test(n))   //如果不符合规则,则撤销这个分支
            {
                visited[i] = 0;
                continue;
            }
            dfs(n + 1);
            visited[i] = 0;
        }
    }
    return ;
}

int main()
{
    dfs(0);
    printf("%d\n", ans);
    return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值