专栏
标签
全国大学生数学建模竞赛,8月19日,第四题打卡
主题活动
发布于 2025-08-21 08:49:46
查看 1过去312天

8月19日 题目四解答说明

题目回顾

今天要解决两个数学问题:

  1. 对sin函数在[0,2π]内进行线性一维插值,并绘图
  2. 找出最小的正整数,满足以下条件:
    • (1) 该数能被7整除
    • (2) 该数的各位数字之和大于20

解题思路

1. sin函数线性插值问题

我的想法:

  • 线性插值就是用直线连接已知点,近似原函数
  • 在[0,2π]区间内选择一些点作为插值节点
  • 用线性插值公式计算中间点的值
  • 比较插值结果和真实值的误差

代码实现:

线性插值函数

function linear_interpolation(x, x_points, y_points)
    # 找到x所在的区间
    for i in 1:length(x_points)-1
        if x >= x_points[i] && x <= x_points[i+1]
            # 线性插值公式:y = y1 + (y2-y1)*(x-x1)/(x2-x1)
            x1, x2 = x_points[i], x_points[i+1]
            y1, y2 = y_points[i], y_points[i+1]
            return y1 + (y2 - y1) * (x - x1) / (x2 - x1)
        end
    end
    return 0.0  # 如果超出范围
end

关键步骤:

  1. 选择插值点:在[0,2π]内均匀选择10个点
  2. 计算插值值:用线性插值公式计算任意点的值
  3. 误差分析:比较插值结果和真实sin值的差异
  4. 结果展示:显示插值效果和误差统计

结果分析:

  • 插值点数量:10个
  • 最大误差:0.059397
  • 平均误差:0.025451
  • 插值效果:在插值点处误差为0,中间点有误差

2. 最小正整数问题

我的想法:

  • 需要找到同时满足两个条件的最小正整数
  • 条件1:能被7整除 → 从7开始,每次加7
  • 条件2:各位数字之和>20 → 需要计算数字各位之和
  • 逐个检查,找到第一个满足条件的数

代码实现:

数字各位之和计算

function digit_sum(n)
    return sum(digits(n))
end

条件检查函数

function satisfies_conditions(n)
    return n % 7 == 0 && digit_sum(n) > 20
end

搜索策略:

  1. 起始点:从7开始(最小的7的倍数)
  2. 步长:每次加7(保证始终是7的倍数)
  3. 检查条件:计算各位数字之和,判断是否>20
  4. 终止条件:找到第一个满足条件的数

搜索过程:

  • 7 → 各位和=7 ✗
  • 14 → 各位和=5 ✗
  • 21 → 各位和=3 ✗
  • ...
  • 399 → 各位和=21 ✓

最终结果:

  • 找到的最小正整数:399
  • 验证:
    • 399 ÷ 7 = 57 ✓
    • 3+9+9 = 21 > 20 ✓

代码实现要点

线性插值部分

  • 插值公式:使用标准的线性插值公式
  • 区间查找:遍历插值点找到x所在的区间
  • 误差计算:用绝对值误差和平均误差评估插值质量
  • 数据展示:对比原始值和插值值

最小正整数部分

  • 数字分解:用digits()函数分解数字各位
  • 条件组合:用逻辑与(&&)组合两个条件
  • 搜索优化:从7开始,每次加7,避免不必要的检查
  • 结果验证:验证找到的数确实满足两个条件

结果总结

  1. 线性插值结果:

    • 插值点:10个均匀分布的点
    • 最大误差:约0.059
    • 平均误差:约0.025
    • 插值效果:在节点处精确,中间有误差
  2. 最小正整数:399

    • 满足条件1:399能被7整除
    • 满足条件2:3+9+9=21 > 20
    • 验证正确

这个问题的关键是理解线性插值的基本原理和如何设计高效的搜索算法。代码实现上要注意函数的正确性和搜索策略的优化。
下面是运行结果
image.png
image.png
image.png
image.png
下面是完整代码

# 使用Syslab (Julia) 解决数学问题

println("=== 8月19日 题目四解答 ===")
println()

# ========================================
# 题目1:对sin函数在[0,2π]内进行线性一维插值,并绘图
# ========================================

println("1. sin函数线性插值问题")
println("=" ^ 50)

# 定义原始sin函数
function original_sin(x)
    return sin(x)
end

# 线性插值函数
function linear_interpolation(x, x_points, y_points)
    # 找到x所在的区间
    for i in 1:length(x_points)-1
        if x >= x_points[i] && x <= x_points[i+1]
            # 线性插值公式:y = y1 + (y2-y1)*(x-x1)/(x2-x1)
            x1, x2 = x_points[i], x_points[i+1]
            y1, y2 = y_points[i], y_points[i+1]
            return y1 + (y2 - y1) * (x - x1) / (x2 - x1)
        end
    end
    return 0.0  # 如果超出范围
end

# 设置插值点
n_points = 10  # 插值点数量
x_interp = range(0, 2π, n_points)  # 均匀分布的插值点
y_interp = [sin(x) for x in x_interp]  # 对应的sin值

println("插值点数量: ", n_points)
println("插值点 x: ", collect(x_interp))
println("插值点 y: ", [round(y, digits=3) for y in y_interp])
println()

# 生成绘图用的密集点
x_plot = range(0, 2π, 1000)
y_original = [original_sin(x) for x in x_plot]
y_interpolated = [linear_interpolation(x, x_interp, y_interp) for x in x_plot]

# 计算插值误差
max_error = maximum(abs.(y_original - y_interpolated))
mean_error = sum(abs.(y_original - y_interpolated)) / length(y_original)

println("插值误差分析:")
println("最大误差: ", round(max_error, digits=6))
println("平均误差: ", round(mean_error, digits=6))
println()

# 绘图:使用简单的文本图形显示
println("绘图:文本形式的sin函数与线性插值对比")
println("=" ^ 60)

# 创建简单的文本图形
function draw_text_plot(x_vals, y_true, y_lin, x_nodes, y_nodes)
    # 选择一些关键点来显示
    step = length(x_vals) ÷ 20  # 显示20个点
    display_points = 1:step:length(x_vals)
    
    println("x值\t\t原始sin(x)\t插值结果\t误差")
    println("-" ^ 60)
    
    for i in display_points
        x_val = x_vals[i]
        orig_val = y_true[i]
        interp_val = y_lin[i]
        error_val = abs(orig_val - interp_val)
        
        # 检查是否是插值节点
        is_node = false
        for j in 1:length(x_nodes)
            if abs(x_val - x_nodes[j]) < 0.01
                is_node = true
                break
            end
        end
        
        node_mark = is_node ? " *" : "  "
        
        println(round(x_val, digits=3), node_mark, "\t", 
                round(orig_val, digits=3), "\t\t", 
                round(interp_val, digits=3), "\t\t", 
                round(error_val, digits=6))
    end
end

# 显示文本图形
draw_text_plot(collect(x_plot), y_original, y_interpolated, collect(x_interp), y_interp)

println()
println("图例说明:")
println("* 标记的点为插值节点(误差为0)")
println("其他点为插值结果(有误差)")
println()
println()

# 显示插值效果对比
println("插值效果对比 (部分点):")
println("x值\t\t原始sin(x)\t插值结果\t误差")
println("-" ^ 60)
for i in 1:10
    x_val = x_plot[i*100]
    orig_val = y_original[i*100]
    interp_val = y_interpolated[i*100]
    error_val = abs(orig_val - interp_val)
    println(round(x_val, digits=3), "\t\t", round(orig_val, digits=3), "\t\t", 
            round(interp_val, digits=3), "\t\t", round(error_val, digits=6))
end
println()

# ========================================
# 题目2:找出最小的正整数,满足以下条件:
# (1) 该数能被7整除
# (2) 该数的各位数字之和大于20
# ========================================

println("2. 最小正整数问题")
println("=" ^ 50)

# 计算数字各位之和的函数
function digit_sum(n)
    return sum(digits(n))
end

# 检查是否满足条件的函数
function satisfies_conditions(n)
    return n % 7 == 0 && digit_sum(n) > 20
end

println("寻找满足条件的最小正整数:")
println("条件1: 能被7整除")
println("条件2: 各位数字之和 > 20")
println()

# 搜索满足条件的最小正整数
function find_smallest_number()
    candidate = 7
    count = 0
    max_search = 10000  # 设置搜索上限

    println("搜索过程:")
    println("候选数\t\t各位数字之和\t是否满足条件")
    println("-" ^ 50)

    while candidate <= max_search
        count += 1
        d_sum = digit_sum(candidate)
        satisfies = satisfies_conditions(candidate)
        
        if count <= 10 || satisfies  # 显示前10个和满足条件的
            status = satisfies ? "✓" : "✗"
            println(candidate, "\t\t", d_sum, "\t\t", status)
        end
        
        if satisfies
            break
        end
        
        candidate += 7
    end

    println()

    if candidate <= max_search
        println("找到满足条件的最小正整数: ", candidate)
        println("验证:")
        println("- 能被7整除: ", candidate, " ÷ 7 = ", candidate ÷ 7, " ✓")
        println("- 各位数字之和: ", digit_sum(candidate), " > 20 ✓")
        return candidate
    else
        println("在搜索范围内未找到满足条件的数")
        return nothing
    end
end

# 执行搜索
result = find_smallest_number()

println()
println("=== 解答完成 ===")

所属专栏:Syslab基础平台
产品信息:Syslab科学计算环境
MWORKS体验官全国大学生数学建模竞赛
附件 2 个附件(36kb)

全部回答

暂无数据
暂无数据
用户
和原帖交流更多问题细节吧,去
我要发帖 我要发帖
资料中心 资料中心
查看更多>
热门帖子 热门帖子
主要贡献者 主要贡献者
过去7天