V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lostexile
V2EX  ›  问与答

咨询一个算法的问题,我是一点思路都没有了。

  •  
  •   lostexile · 63 天前 · 1966 次点击
    这是一个创建于 63 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想给女儿出一些计算题目,于是自己写了个简单的脚本。

    现在遇到一个问题,我想要输出 5 个数字以内的四则运算算式,每个数字都有可能是 5 位数以内的自然数。

    基于计算训练的需求,我想要保证结果必须为整数。 就是想出一些 131328÷27÷256=19 这种的算式,孩子自己就能快速的知道计算是不是有错误。

    但是我发现在生成的算式的时候效率非常低,经常遇到卡死的情况。 于是我在生成前增加了一个校验的逻辑,就是输入一下配置,先看一下这个配置能生成多少个算式,如果符合条件的算式数量比较小,比如为 0 ,或者小于 10 ,就直接提示配置不合理。

    现在我被这个检查配置的逻辑卡住了,完全没有思路如何高效的去计算符合配置的算式数量。 请问各位大佬有思路么。

    24 条回复    2025-07-12 00:19:48 +08:00
    corcre
        1
    corcre  
       63 天前
    先生成乘法公式, 然后转换成除法, 例如生成 19*27*256=131328, 然后转换成除法 131328÷27÷256=19 🐶
    Junzh
        2
    Junzh  
       63 天前
    我建议你反过来思考,先确定这个整体,再依次去乘。
    coderluan
        3
    coderluan  
       63 天前
    反过来想啊,先随机一个整数,然后乘随机数,你只要确保结果不超出五位就行了吧。
    weenhall5
        4
    weenhall5  
       63 天前
    这个交给 ai 不是更好吗
    Junzh
        5
    Junzh  
       63 天前
    先确定这个整数,如果全是除法的话,就反过来去乘。
    lostexile
        6
    lostexile  
    OP
       63 天前
    AI 已经问过了,
    目前 DeepSeek ,豆包,ChatGPT ,cursor ,火山已经全线阵亡,目前给我最靠谱的答案就是跑完结果之后缓存下来,下次再来请求直接用缓存的数据求和计算。


    至于用乘法生成的方案,不是没考虑过,但是现在我有两个问题:
    1. 先用乘法的话,我要如何控制被除数的位数,因为相当于乘法的两个因数都不知道位数的情况下去控制结果的位数。
    2. 相同的逻辑,我想要生成小数乘以小数,但是结果必须为整数,也需要校验。


    所以我想咨询一下有木有数学方面的大佬,有没有方面的我不了解的数学逻辑,可以直接计算的那种。
    gg1025
        7
    gg1025  
       63 天前
    "每个数字都有可能是 5 位数以内的自然数" 建议直接打表
    newaccount
        8
    newaccount  
       63 天前
    10^3 * 10^3 = 10^6
    感觉上,反向计算乘法的时候,只要知道剩下可用的位数,就可以确定下一个数的取值范围
    大概就是 pow(10, N),只要确定这个 N 的范围,然后 rand(N) 就可以?
    另外为了保证结果算式能有不少于 M 个式子,每一步可以提前减去当前已生成的参数个数
    suiterchik
        9
    suiterchik  
       63 天前
    如果不需要支持括号优先级的话应该还好?初始化一个随机的数值 x1 ,并创建一个 answer 变量 answer = 1

    然后从加减乘除中随机选一个操作

    * 如果是加法,则下个数字 x2 的取值范围是 [0, 99999 - answer] 中随机取一个整数,确保 answer + x2 < 99999 ,如果找不到则这一步步采用加法;

    * 如果是减法,则下个数字 x2 的取值范围是 [0, answer] 中随机取一个数,确保 answer - x2 > 0 ,如果找不到则这一步不采用减法;

    * 如果是乘法,则下个数字 x2 的取值范围是 [0, 99999 / answer], 随机取一个整数,确保 answer * x2 < 99999 ,如果找不到则这一步不采用乘法;

    * 如果是除法,则计算 answer 的公约数,然后从公约数列表 [y1, y2, y3...] 中任取 k 个乘起来作为 x2 ,确保 answer / x2 为整数,如果 answer 为素数则这一步不采用除法

    然后根据你这步采用哪个 op ,以及对应的数值,更新 answer 变量,进入下一个数字 x3 的操作,x3 的选取与 x2 的逻辑一样,重复直到 x5 选取完毕
    suiterchik
        10
    suiterchik  
       63 天前
    @suiterchik answer 变量初始化应该是 answer = x1 ,敲少了个字母
    play78
        11
    play78  
       63 天前
    你有没有想过现在的计算机已经很强大了。随便暴力都可以生成出来。如果只是为了给小孩出题,那怎么简单怎么来。如果要研究纯数学算法,那就比较难了。
    ```js
    for(var i=0; i<10000; i++){
    var a = Math.floor(Math.random()*99999);
    var b = Math.floor(Math.random()*99999);
    var c = Math.floor(Math.random()*99999);
    var f = "+-*/";
    var d1 = f[Math.floor(Math.random()*f.length)];
    // var d2 = f[Math.floor(Math.random()*f.length)];
    var d2;
    do {
    d2 = f[Math.floor(Math.random()*f.length)];
    } while (d1 !== '/' && d2 !== '/'); //保证一定包含除法
    var exp = a+d1+b+d2+c;
    var v = eval(exp);
    if(v % 1 !== 0){
    continue;
    }
    if(v > 99999 || v < 0){
    continue;
    }
    console.log(exp + "=" + v);
    }
    ```
    39151+97515/55=40924
    77223-34790/71=76733
    72451-64843/61=71388
    43332/471+74553=74645
    34143*66638/68286=33319
    LandCruiser
        12
    LandCruiser  
       63 天前
    先生成乘法就蛮好的,5 位数最大是 99999 ,max = 99999 所以 a,b = random ( 0 ,max ) if a*b <max; print [a]*[b] /a = a*b
    然后还可以优化,比如 if a*b>max; a = a - 1 b= b -1
    suiterchik
        13
    suiterchik  
       63 天前
    @suiterchik 噢这里还有个问题,乘除的优先级比加法高,所以你还需要把 x1, x2, .., x5 构建出 ast ,然后再解析成正确的表达式,否则会出现 1 + 2 x 3 = 9 的错误
    piku
        14
    piku  
       63 天前 via Android
    我想要输出 5 个数字以内的四则运算算式,每个数字都有可能是 5 位数以内的自然数。
    基于计算训练的需求,我想要保证结果必须为整数。
    这块没看懂,是说有 a b c d e 这样 5 个随机整数或小数且每个数字都<=99999 ,配合+-×÷4 个随机运算符号,运算结果也<=99999 ?
    假设完全随机穷举出了符合要求的算式且结果不为整数,那么将结果取整后反推一下,改变 e 的值就好了啊?比如(3+4)/6=1.1666 ,取整为 1 ,反推纠正为( 3+4 )/7=1
    GeruzoniAnsasu
        15
    GeruzoniAnsasu  
       63 天前
    ? 这还能卡死

    随机一个数作为答案,再随机几个步骤得到初始数字,再根据优先级规则打乱顺序并补上括号

    如果发现数字过大,那就每个中间数字比较一下离数字域上限有多近,乘一个权重来随机是往上涨还是往下缩

    如果发现经常摇不出可以整除的数字就动态规划一下,把当前数字乘上来的路径记住,从可行路径里选一个

    如果可选路径数量太少就先因式分解打一个表( 2*2,2*3,2*5,...2*2*2,2*2*3,...)
    Gavin999
        16
    Gavin999  
       63 天前
    搞这么麻烦 还写脚本 一个计算器不就解决了吗
    tool2dx
        17
    tool2dx  
       63 天前
    小学计算题,代码怎么可能卡死,我是非常不理解.

    用乘法去倒推,暴力循环都能搞定的事情.
    geelaw
        18
    geelaw  
       63 天前 via iPhone   ❤️ 1
    很神秘,因为看完主贴之后我的问题是:什么是“配置”?不交代什么是“配置”则连要解决的问题是什么都不知道。

    很多没有思路是从没有清楚表述问题开始的。
    kamilic
        19
    kamilic  
       63 天前
    我觉得你可以通过遍历预先生成一大堆随机相乘的式子和结果( axb, axbxc, axbxcxd, .....)。
    乘法问题直接在集合里面随机取,除法问题可以通过乘法问题进行转换得到。
    加减法本身就能自由组合,你甚至可以把乘法中的数字拆成加减法问题做一点变种,只要等号两侧能配平随便你玩。
    JoeJoeJoe
        20
    JoeJoeJoe  
    PRO
       63 天前
    直接用 ai 生成了一个 python 的:

    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # Author: Joe
    # Description: 生成 10000 以内的小学计算题

    import random

    def generate_operation():
    """生成一个四则运算表达式,保证结果为整数"""
    operators = ['+', '-', '*', '÷'] # 将 '/' 替换为 '÷'
    # 计算长度 1 到 5 次
    count = random.randint(1, 5)
    # 减少小数出现的次数,约 30% 的概率为小数
    numbers = []
    for _ in range(count + 1):
    if random.random() < 0.3:
    num = round(random.uniform(1, 10000), 2) # 最多保留两位小数
    else:
    num = random.randint(1, 10000)
    numbers.append(num)

    ops = [random.choice(operators) for _ in range(count)]

    expression = str(numbers[0])
    for i in range(count):
    while ops[i] == '÷' and numbers[i + 1] == 0: # 修改为 '÷'
    if random.random() < 0.3:
    numbers[i + 1] = round(random.uniform(1, 10000), 2)
    else:
    numbers[i + 1] = random.randint(1, 10000)
    # 确保除法运算结果为整数
    if ops[i] == '÷': # 修改为 '÷'
    # 计算商并确保至少为 1
    quotient = max(1, int(numbers[i] // numbers[i + 1]))
    # 调整被除数使其为除数的整数倍
    numbers[i] = numbers[i + 1] * random.randint(1, quotient)
    expression += f" {ops[i]} {numbers[i + 1]}"

    result = eval(expression.replace('÷', '/')) # 计算时将 '÷' 替换回 '/'
    # 确保结果为整数
    while isinstance(result, float) and not result.is_integer():
    numbers = []
    for _ in range(count + 1):
    if random.random() < 0.3:
    num = round(random.uniform(1, 10000), 2)
    else:
    num = random.randint(1, 10000)
    numbers.append(num)
    ops = [random.choice(operators) for _ in range(count)]
    expression = str(numbers[0])
    for i in range(count):
    while ops[i] == '÷' and numbers[i + 1] == 0: # 修改为 '÷'
    if random.random() < 0.3:
    numbers[i + 1] = round(random.uniform(1, 10000), 2)
    else:
    numbers[i + 1] = random.randint(1, 10000)
    if ops[i] == '÷': # 修改为 '÷'
    quotient = max(1, int(numbers[i] // numbers[i + 1]))
    numbers[i] = numbers[i + 1] * random.randint(1, quotient)
    expression += f" {ops[i]} {numbers[i + 1]}"
    result = eval(expression.replace('÷', '/')) # 计算时将 '÷' 替换回 '/'

    return expression, int(result)

    # 生成题目和结果
    expression, result = generate_operation()
    # 打印题目
    print(f"题目: {expression}")
    # 打印结果
    print(f"结果: {result}")
    JoeJoeJoe
        22
    JoeJoeJoe  
    PRO
       63 天前
    @JoeJoeJoe #20 小数有点不太对 你可以再自己改改, 整数处理的感觉没啥大问题, 代码我也没细看😂
    guyeu
        23
    guyeu  
       63 天前
    典型 xy 问题,你的需求是生成包含 n 个五位和五位以内数字的四则运算算式,并隐藏其中一个数,但是你问的是怎么样去检查你的配置(你的逻辑、参数、配置都没有提前解释)。
    cloudzhou
        24
    cloudzhou  
       63 天前   ❤️ 1
    你的表达能力有待提高,不是很明白你说什么
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2844 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 02:17 · PVG 10:17 · LAX 19:17 · JFK 22:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.