ITPub博客

首页 > 数据库 > Oracle > [20250527]24点计算2.txt

[20250527]24点计算2.txt

原创 Oracle 作者:lfree 时间:2025-05-29 20:21:03 0 删除 编辑

[20250527]24点计算2.txt

--//有一张表 cards,id 是自增字段的数字主键,另外有4个字段 c1,c2,c3,c4 ,每个字段随机从 1~10 之间选择一个整数,要求选手
--//使用一条 SQL 给出 24 点的计算公式.

--//单独写出一条sql语句有点难度,我先尝试使用sqlplus+ bash shell的方式实现看看,计算使用dc或者bc。
--//实际上sqlplus一般采用穷举方法计算,蛮力计算结果是否等于24,使用sqlplus,要根据运算符号计算2个数字的计算结果,每次运
--//算都是如此,处理难度集中在哪里,而且题目并没有除法时必须整除,另外运算除法时分母是0该如何处理。我简单一点,直接使用
--//sql语句写出运算的排列组合,然后交给dc或者bc计算,我并没有建立表,先尝试直接带入4个数字计算。

--//运算符号 + - * / ,参与运算3次,这样排列组合就是4*4*4=64种。
--//数字是4个,排列组合就是4*3*2*1=24种。

--//计算方法最简单2个数字运算,再加入1个数字运算,再加入1个数字运算。取一个例子:1 7 8 9,计算如下:
1*7=7
7+8=15
15+9=24

--//写成计算公式如下:
1*7+8+9
--//但是具体公式不能这样写,加减乘除有优先级,必须写成:
((1*7)+8)+9
--//这样计算,我自己称为method 1,实际上测试大部分都可以通过该方法实现。还有一种两两计算,然后计算结果在计算1次。
--//我称为method 2,这样排列组合出现的情况有5种:
## method 1: ((n1 p1 n2 ) p2 n3)  p3 n4
## method 2: ( n1 p1 n2 ) p3 (n3  p2 n4)
## method 3: ( n1 p2 (n2  p1 n3)) p3 n4
## method 4:   n1 p3 (n2  p2  (n3 p1 n4))
## method 5:  n1  p3 ((n2 p1 n3) p2 n4)
--//注:n1,n2,n3,n4表示数字,p1,p2,p3表示运算符。

--//使用dc与bc 计算问题,oracle计算必须规避除法分母为0的问题,精度问题我估计问题不大。
--//使用dc与bc 存在如下问题。
1.精度问题:
SCOTT@book01p> select 1/ 3* 9 *8 from dual ;
   1/3*9*8
----------
        24
--//而使用dc 与bc不行,比如:
$ echo "10/ 4* 10 + 4 " |bc
24
--//这明显计算错误,必须带入精度
$ echo "10/ 4* 10 + 4 " |bc -l
29.00000000000000000000

--//带入精度出现另外的问题,计算误差,例子:
$ echo "1/ 3* 9 *8 " |bc -l
23.99999999999999999976
--//不过这个问题影响不大,能计算出如此接近的结果,排列组合里面一定存在合适的情况。
--//dc的情况也是类似。
$ echo "20k 1  3 /  9 * 8 * pq " |dc
23.99999999999999999976

2.分母为0的情况:
--//执行dc的情况:
$ echo "20k 1 0 / pq " |dc
dc: divide by zero
0

$ echo "20k 1 0 / pq " |dc 2>/dev/null
0
--//只要将错误重定向到/dev/null就可以了。

$ echo " 1 / 0  " |bc -l
Runtime error (func=(main), adr=3): Divide by zero

$ echo " 1 / 0  " |bc -l 2>/dev/null
--//没有输出。这样bash shell编程要注意使用双引号。

3.还是与精度有关的问题:
$ echo "(( 2 * 7) + 1) + 9 " | bc -l
24

$ echo "20k 2 7 * 1 + 9 +  pq" |dc
24
--//即使我指定精度,注bc -l 设定scale=20. 但是如果整形运算,结尾有一些情况也不会输出0.这样在判断上要加入一个或判断。
--//我取了一个巧,再使用1做除法,就可以输出小数点结尾后为0的情况。

$ echo "(( 2 * 7) + 1) + 9 /1" | bc -l
24.00000000000000000000

 $ echo "20k 2 7 * 1 + 9 + 1 / pq" |dc
24.00000000000000000000

$ ./24doty.sh 1 3 9 8
1 3 9 8 : method 1:20k 1 8 * 9 * 3 / 1 / pq:(( 1 * 8) * 9) / 3
--//如果加入参数5输入all,输出全部结果。
--//我尝试全部组合共715种,发现一些有趣的解法:比如 1 5 5 5,按照道理算不出24.穷举可以找到2个:
$ ./24doty.sh 1 5 5 5 all
1 5 5 5 : method 3:20k 5 1 5 / - 5 * 1 / pq:( 5 - ( 1 / 5)) * 5
1 5 5 5 : method 4:20k 5 5 1 5 / - * 1 / pq: 5 * ( 5 - ( 1 / 5))

$ ./24doty.sh 6 9 9 10 all
6 9 9 10 : method 1:20k 9 6 / 10 * 9 + 1 / pq:(( 9 / 6) * 10) + 9
6 9 9 10 : method 1:20k 9 10 * 6 / 9 + 1 / pq:(( 9 * 10) / 6) + 9
6 9 9 10 : method 1:20k 10 9 * 6 / 9 + 1 / pq:(( 10 * 9) / 6) + 9
6 9 9 10 : method 3:20k 9 6 10 / / 9 + 1 / pq:( 9 / ( 6 / 10)) + 9
6 9 9 10 : method 3:20k 10 9 6 / * 9 + 1 / pq:( 10 * ( 9 / 6)) + 9
6 9 9 10 : method 4:20k 9 9 6 10 / / + 1 / pq: 9 + ( 9 / ( 6 / 10))
6 9 9 10 : method 4:20k 9 10 9 6 / * + 1 / pq: 9 + ( 10 * ( 9 / 6))
6 9 9 10 : method 5:20k 9 9 6 / 10 * + 1 / pq: 9 + (( 9 / 6) * 10)
6 9 9 10 : method 5:20k 9 9 10 * 6 / + 1 / pq: 9 + (( 9 * 10) / 6)
6 9 9 10 : method 5:20k 9 10 9 * 6 / + 1 / pq: 9 + (( 10 * 9) / 6)
--//找到第1个 (( 9 / 6) * 10) + 9。

$ grep "method [345]" js24.txt | sort -t: -k2
3 5 10 10 : method 3:20k 10 10 5 / - 3 * 1 / pq:( 10 - ( 10 / 5)) * 3
4 5 5 8 : method 3:20k 4 5 5 / - 8 * 1 / pq:( 4 - ( 5 / 5)) * 8
4 8 9 9 : method 3:20k 4 9 9 / - 8 * 1 / pq:( 4 - ( 9 / 9)) * 8
1 5 5 5 : method 3:20k 5 1 5 / - 5 * 1 / pq:( 5 - ( 1 / 5)) * 5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 5 5 10 : method 3:20k 5 2 10 / - 5 * 1 / pq:( 5 - ( 2 / 10)) * 5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 6 6 6 : method 3:20k 5 6 6 / - 6 * 1 / pq:( 5 - ( 6 / 6)) * 6
5 6 7 7 : method 3:20k 5 7 7 / - 6 * 1 / pq:( 5 - ( 7 / 7)) * 6
4 7 10 10 : method 3:20k 7 10 10 / - 4 * 1 / pq:( 7 - ( 10 / 10)) * 4
4 5 5 7 : method 3:20k 7 5 5 / - 4 * 1 / pq:( 7 - ( 5 / 5)) * 4
4 7 7 7 : method 3:20k 7 7 7 / - 4 * 1 / pq:( 7 - ( 7 / 7)) * 4
4 7 9 9 : method 3:20k 7 9 9 / - 4 * 1 / pq:( 7 - ( 9 / 9)) * 4
3 9 10 10 : method 3:20k 9 10 10 / - 3 * 1 / pq:( 9 - ( 10 / 10)) * 3
3 3 3 9 : method 3:20k 9 3 3 / - 3 * 1 / pq:( 9 - ( 3 / 3)) * 3
3 7 7 9 : method 3:20k 9 7 7 / - 3 * 1 / pq:( 9 - ( 7 / 7)) * 3
1 3 4 6 : method 4:20k 6 1 3 4 / - / 1 / pq: 6 / ( 1 - ( 3 / 4))
1 6 6 8 : method 4:20k 6 1 6 8 / - / 1 / pq: 6 / ( 1 - ( 6 / 8))
1 4 5 6 : method 5:20k 6 5 4 / 1 - / 1 / pq: 6 / (( 5 / 4) - 1)
--//大部分使用method 1,2都可以解决。method 5有1条,method 4有2条,而且解法都非常"特殊"。
--//method 3有14条,解法比较特殊的有2条。

$ grep "fail" js24.txt |wc
    153     918    2390
--//无法计算得到24仅仅153种情况。

$ cut -d: -f4 js24dc1.txt |  grep -Po "[+\-*/]+" | paste - - - | sort | uniq -c | sort -nr
     55 -       +       *
     41 +       +       +
     38 *       +       +
     38 *       -       *
     36 +       *       -
     34 -       *       +
     32 +       -       *
     27 +       *       +
     21 +       /       *
     19 *       -       +
     18 *       +       -
     16 -       *       -
     16 -       /       *
     15 /       +       *
     14 -       +       +
     13 *       -       -
     12 +       +       *
     12 *       +       *
     11 *       *       +
      9 /       *       +
      9 -       *       *
      9 -       -       *
      8 +       *       *
      8 *       *       -
      8 *       -       /
      8 /       *       *
      7 *       *       /
      5 +       *       /
      4 *       *       *
      3 *       +       /
      3 *       /       +
      3 *       /       *
      3 *       /       -
      2 /       +       +
      2 /       -       /
      1 /       *       -
      1 /       /       -
      1 -       *       /

--//源代码如下:
$ cat 24dot.sh
#! /bin/bash

all=${5:-0}
#echo $all

tmpfile=$(mktemp)

sqlplus -s -l / as sysdba  <<EOF >| ${tmpfile}
set pagesize 0
set head off echo off verify off  feed off COLSEP ':'
WITH x1
        AS (SELECT 1 id, ' +' c FROM DUAL
            UNION ALL
            SELECT 8 id, ' -' FROM DUAL
            UNION ALL
            SELECT 1.2 id, ' *' FROM DUAL
            UNION ALL
            SELECT 16 id, ' /' FROM DUAL)
    ,x2
        AS (  SELECT decode(replace(x1.c||x2.c||x3.c,' ','')
,'-+*',-55
,'+++',-41
,'*++',-38
,'*-*',-38
,'+*-',-36
,'-*+',-34
,'+-*',-32
,'+*+',-27
,'+/*',-21
,'*-+',-19
,'*+-',-18
,'-*-',-16
,'-/*',-16
,'/+*',-15
,'-++',-14
,'*--',-13
,'++*',-12
,'*+*',-12
,'**+',-11
,x1.id + x2.id + x3.id) idop
                    ,x1.c p1
                    ,x2.c p2
                    ,x3.c p3
                FROM x1, x1 x2, x1 x3
            ORDER BY 1 )
    ,y1
        AS (SELECT 1 id, to_char($1,'999') n FROM DUAL
            UNION ALL
            SELECT 2 id, to_char($2,'999') FROM DUAL
            UNION ALL
            SELECT 3 id, to_char($3,'999') FROM DUAL
            UNION ALL
            SELECT 4 id, to_char($4,'999') FROM DUAL)
    ,y2
        AS (  SELECT DISTINCT x1.n n1
                             ,x2.n n2
                             ,x3.n n3
                             ,x4.n n4
                FROM y1 x1
                    ,y1 x2
                    ,y1 x3
                    ,y1 x4
               WHERE     x1.id <> x2.id
                     AND x1.id <> x3.id
                     AND x1.id <> x4.id
                     AND x2.id <> x3.id
                     AND x2.id <> x4.id
                     AND x3.id <> x4.id
            ORDER BY 1 ,2 ,3 ,4)
--select txt,dc1,bc2 from (
SELECT 'method 1' txt, '20k '||n1||n2||p1||n3||p2||n4||p3 dc1,'(('||n1||p1||n2||')'||p2||n3||')'||p3||n4 bc2 FROM y2, x2
union all
SELECT 'method 2' txt, '20k '||n1||n2||p1||n3||n4||p2||p3 dc1,'('||n1||p1||n2||')'||p3||'('||n3||p2||n4||')' bc2 FROM y2, x2
union all
SELECT 'method 3' txt, '20k '||n1||n2||n3||p1||p2||n4||p3 dc1,'('||n1||p2||'('||n2||p1||n3||'))'||p3||n4 bc2 FROM y2, x2
union all
SELECT 'method 4' txt, '20k '||n1||n2||n3||n4||p1||p2||p3 dc1, n1||p3||'('||n2||p2||'('||n3||p1||n4||'))' bc2 FROM y2, x2
union all
SELECT 'method 5' txt, '20k '||n1||n2||n3||p1||n4||p2||p3 dc1, n1||p3||'(('||n2||p1||n3||')'||p2||n4||')' bc2 FROM y2, x2
--) where TO_NUMBER(XMLQUERY(replace(bc2,'/','div') RETURNING CONTENT))=24 --and rownum=1
;
quit
EOF

#/bin/cp ${tmpfile} e3.txt
sed -i "s/ \{2,\}/ /g" ${tmpfile}
#exit

## method 1: ((n1 p1 n2 ) p2 n3)  p3 n4
## method 2: ( n1 p1 n2 ) p3 (n3  p2 n4)
## method 3: ( n1 p2 (n2  p1 n3)) p3 n4
## method 4:   n1 p3 (n2  p2  (n3 p1 n4))
## method 5:  n1  p3 ((n2 p1 n3) p2 n4)

result='bad'
while read line
do
    #echo "$line"
    filed1=$(echo "$line"| cut -d":" -f1)
    filed2=$(echo "$line"| cut -d":" -f2)
    filed3=$(echo "$line"| cut -d":" -f3)
    res=$(echo "$filed2 1 / pq" | dc 2>/dev/null)
    #res=$(echo "scale=20 ; $filed3 /1" | bc  2>/dev/null)
    if [ "${res}" = '24.00000000000000000000' ]
    then
        echo "$1 $2 $3 $4 : $line"
        result='ok'
        #return 1
        if [ ${all} != 'all' ]
        then
            break
        fi
    fi
done < ${tmpfile}

if [ $result != 'ok' ]
then
   echo "$1 $2 $3 $4 : fail"
fi

/bin/rm  ${tmpfile}

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-3086211/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4006
  • 访问量
    7969894