[CDOJ1252]-24点-模拟/搜索

本文介绍了一种解决24点游戏的算法实现方法,通过深度优先搜索(DFS)策略来判断给定的四个数字是否可以通过加减乘除运算得到24。文章详细解释了算法流程,并提供了一个具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说在前面

机房的大佬给我们找了一堆搜索题练习代码量,然后me挑了一道写…
然而这题一点都不考代码量,想一想怎么写比较简单,剩下的事情就是复制粘贴了=w=
(论如何在10分钟之内写完一道搜索题)


题目

CDOJ1252传送门

题面

24点就是给你一串数字,问你是否通过加减乘除括号构成24点。
沈爷觉得这个很好玩,就决定考考你,给你4个数,可以交换位置,可以用加减乘除和括号,是否能构成24点呢?
注意哦~这里的除法并不是整数除法,比如样例

输入及输出

输入:
第一行T,表示有多少组测试数据,1≤T≤50
接下来T行,每行4个正整数a1, a2, a3, a4,表示每个数都是多少,其中1≤ai≤13
输出:
对于每一次询问,如果能够凑成24点,输出yes,否则输出no

样例

输入:
2
3 3 8 8
1 1 1 1
输出:
yes
no


解法

题面说的什么交换顺序啊,括号啊什么的,其实就是随意顺序,不要想复杂啦。

然后呢,模拟(暴搜)的时候大概是这样的:
当me还没有进行运算的时候,me有四个数。
第一次运算,me就会从初始的四个数中选两个数出来进行运算,然后me还剩三个数
第二次运算,me就会从剩下的三个数里面选出两个数进行运算,然后me还剩两个数
第三次运算,me会将剩下的两个数进行运算,最后剩下一个数
第四次,me只需要检查当前剩下的数是否是24就可以了

然后写个dfs就可以水过,复杂度:( 6 * 6 ) * ( 3 * 6 ) * ( 2 * 6 ),每个括号表示一层,括号内第一个数字表示从剩下的数里选择两个数的方案数,第二个表示运算种数(减法和除法各有两种,因为有方向)

注意使用除法的时候记得判定除数不能为0,还有要注意eps


下面是自带大常数的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

int T ;
double num[5][5] , eps = 1e-8 ;

int dcmp( double x ){
    if( x > -eps && x < eps ) return 0 ;
    return ( x > 0 ? 1 : -1 ) ;
}

bool dfs( int dep ){
    //printf( "dep = %d : %f %f %f %f\n" , dep , num[dep][1] , num[dep][2] , num[dep][3] , num[dep][4] ) ; getchar() ;
    if( dep == 4 ){
        if( dcmp( num[dep][1] - 24.0 ) == 0 ) return true ;
        return false ;
    }
    int topp = 0 ;
    for( int i = 1 ; i < 4 - dep + 1 ; i ++ ){
        for( int j = i + 1 ; j <= 4 - dep + 1 ; j ++ ){
            //add
            topp = 0 ;
            for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
            num[dep+1][++topp] = num[dep][i] + num[dep][j] ;
            if( dfs( dep + 1 ) ) return true ;
            //minus i-j
            topp = 0 ;
            for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
            num[dep+1][++topp] = num[dep][i] - num[dep][j] ;
            if( dfs( dep + 1 ) ) return true ;
            //minus j-i
            topp = 0 ;
            for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
            num[dep+1][++topp] = num[dep][j] - num[dep][i] ;
            if( dfs( dep + 1 ) ) return true ;
            //multiply
            topp = 0 ;
            for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
            num[dep+1][++topp] = num[dep][i] * num[dep][j] ;
            if( dfs( dep + 1 ) ) return true ;
            //division i/j
            if( dcmp( num[dep][j] ) != 0 ){
                topp = 0 ;
                for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                    if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
                num[dep+1][++topp] = num[dep][i] / num[dep][j] ;
                if( dfs( dep + 1 ) ) return true ;
            }
            //division j/i
            if( dcmp( num[dep][i] ) != 0 ){
                topp = 0 ;
                for( int k = 1 ; k <= 4 - dep + 1 ; k ++ )
                    if( k != i && k != j ) num[dep+1][++topp] = num[dep][k] ;
                num[dep+1][++topp] = num[dep][j] / num[dep][i] ;
                if( dfs( dep + 1 ) ) return true ;
            }
        }
    }
    return false ;
}

int main(){
    scanf( "%d" , &T ) ;
    for( int i = 1 ; i <= T ; i ++ ){
        for( int j = 1 ; j <= 4 ; j ++ )
            scanf( "%lf" , &num[1][j] ) ;
        puts( dfs( 1 ) ? "yes" : "no" ) ;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值