《算法竞赛·快冲300题》每日一题:“凑二十四”

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。


凑二十四” ,链接: http://oj.ecustacm.cn/problem.php?id=1793

题目描述

【题目描述】 给你n个数字,你需要在n-1个间隔中添加符号+、-、×,按照正常优先级计算结果。请你输出有多少种方案,计算结果等于24。
【输入格式】 第一行为正整数n(2≤n≤10)。第二行n个正整数表示给定的n个数字,数字不超过50。
【输出格式】 输出一个数字表示答案。
【输入样例】

5
2 4 6 8 16

【输出样例】

2

题解

   如果尝试所有可能组合,共有多少种组合?最多n=10个数字时,需要添加9个符号,共 3 9 = 19683 3^9=19683 39=19683种组合,并不多。
  用DFS搜索所有可能组合。由于只有19683种情况,不用剪枝。
  代码用dfs()搜索所有符号组合。对每个组合,用check()检查计算结果是否等于24。先计算乘法,再计算加减。下面的代码用了简单直接的模拟法。先处理表达式中的乘法,对两个数做乘法时,把计算结果存在后面,前面置零,并把符号改为前面的加减,例如3+4×5,先处理乘法,转换为3+0+20。
  check()也有其他写法,例如先把表达式(称为中缀表达式)转为逆波兰表达式,然后用栈来计算逆波兰表达式。因为比较繁琐,这里没有给出代码。
【重点】 DFS 。

C++代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, a[11];
int op[11];               //第i个间隔的符号 + - * = 0 1 2
int ans;
ll check(){   //先计算*,再计算+-
    ll t[11] = {0}, t_op[11] = {0};
    for(int i=1; i<=n; i++)
        t[i] = a[i], t_op[i] = op[i];
    //先处理乘号:把乘积结果存入t[i+1]、t[i]设置为0、符号沿用前面的符号
    for(int i = 1; i < n; i++)
        if(t_op[i] == 2)
            t[i+1] *= t[i], t[i] = 0, t_op[i] = t_op[i-1];
    //最后加减
    ll sum = t[1];
    for(int i = 1; i < n; i++){
        if(t_op[i] == 0)  sum += t[i+1]; //加
        else sum -= t[i+1];              //减
    }
    return sum;
}
void dfs(int depth){
    if(depth == n){
        if(check() == 24)   ans++;
        return;
    }
    for(int i = 0; i <= 2; i++) {   //继续添加下一个符号
        op[depth] = i;
        dfs(depth + 1);
    }
}
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++)    cin >> a[i];
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

Java代码

import java.util.Scanner;
public class Main {
    static int n, a[] = new int[11], op[] = new int[11]; // 第i个间隔的符号 + - * = 0 1 2
    static int ans;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        for (int i = 1; i <= n; i++)   a[i] = in.nextInt();
        dfs(1);
        System.out.println(ans);
        in.close();
    }
    static long check() { // 先计算*,再计算+-
        long[] t = new long[11];
        int[] t_op = new int[11];
        for (int i = 1; i <= n; i++) {
            t[i] = a[i];
            t_op[i] = op[i];
        }
        // 先处理乘号:把乘积结果存入t[i+1]、t[i]设置为0、符号沿用前面的符号
        for (int i = 1; i < n; i++) {
            if (t_op[i] == 2) {
                t[i + 1] *= t[i];
                t[i] = 0;
                t_op[i] = t_op[i - 1];
            }
        }
        // 最后加减
        long sum = t[1];
        for (int i = 1; i < n; i++) {
            if (t_op[i] == 0) sum += t[i + 1]; // 加
            else              sum -= t[i + 1]; // 减
        }
        return sum;
    }
    static void dfs(int depth) {
        if (depth == n) {
            if (check() == 24)   ans++;
            return;
        }
        for (int i = 0; i <= 2; i++) { // 继续添加下一个符号
            op[depth] = i;
            dfs(depth + 1);
        }
    }
}

Python代码

n = int(input())
a = [0]+list(map(int, input().split()))     #输入到a[1]-a[10]
op = [0] * 11                               # 第i个间隔的符号 + - * = 0 1 2
ans = 0
def check():# 先计算*,再计算+-
    t = [0] * 11
    t_op = [0] * 11
    for i in range(1, n+1):
        t[i] = a[i]
        t_op[i] = op[i]
    # 先处理乘号:把乘积结果存入t[i+1]、t[i]设置为0、符号沿用前面的符号
    for i in range(1, n):
        if t_op[i] == 2:
            t[i+1] *= t[i]
            t[i] = 0
            t_op[i] = t_op[i-1]
    # 最后加减
    sum = t[1]
    for i in range(1, n):
        if t_op[i] == 0: sum += t[i+1]  # 加
        else:            sum -= t[i+1]  # 减
    return sum
def dfs(depth):
    global ans
    if depth == n:
        if check() == 24:   ans += 1
        return
    for i in range(3):                  # 继续添加下一个符号
        op[depth] = i
        dfs(depth + 1)
dfs(1)
print(ans)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
算法竞赛是一个非常有趣和具有挑战性的领域,对于入门者来说,掌握一些经典的习是非常重要的。下面是一些算法竞赛入门经典习的讲解: 1. 两数之和:给定一个整数数组和一个目标值,在数组中找出和为目标值的两个数。可以假设每个输入都只有一个解,并且同一个元素不能使用两次。这个问可以使用哈希表来解决,时间复杂度为O(n)。 2. 最大子序和:给定一个整数数组,找到一个具有最大和的连续子数组。例如,对于数组[-2,1,-3,4,-1,2,1,-5,4],其最大子序和为6(子数组为[4,-1,2,1])。这个问可以使用动态规划来解决,时间复杂度为O(n)。 3. 两数相加:给定两个非空链表,表示两个非负整数。它们每位数字都是按照逆序方式存储的,并且每个节点只能存储一位数字。将这两个数相加并以相同形式返回一个新的链表。例如,输入(2 -> 4 -> 3) + (5 -> 6 -> 4),输出7 -> 0 -> 8。这个问可以使用链表的基本操作来解决,时间复杂度为O(max(m,n)),其中m和n分别是两个链表的长度。 4. 最长回文子串:给定一个字符串,找到其中最长的回文子串。例如,对于字符串"babad",最长的回文子串为"bab"或"aba"。这个问可以使用动态规划或中心扩展法来解决,时间复杂度为O(n^2)。 5. 二叉树的最大深度:给定一个二叉树,找出其最大深度。最大深度是从根节点到最远叶子节点的最长路径上的节点数。例如,对于二叉树[3,9,20,null,null,15,7],其最大深度为3。这个问可以使用递归来解决,时间复杂度为O(n),其中n是二叉树中的节点数。 以上是一些算法竞赛入门经典习的讲解,希望能对你有所帮助。在算法竞赛中,不仅要熟悉各种经典目的解法,还要注重实践和思考,提高自己的编程能力和算法思维。祝你在算法竞赛中取得好成绩!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗勇军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值