楼主: newkid

[精华] 深夜独霸, 轮到我出个题目了——算24点的SQL解法

[复制链接]
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
71#
 楼主| 发表于 2008-10-5 04:04 | 只看该作者
lastwinner 也来写一个吧!

使用道具 举报

回复
论坛徽章:
8
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:442009日食纪念
日期:2009-07-22 09:30:002010新春纪念徽章
日期:2010-01-04 08:33:082010新春纪念徽章
日期:2010-03-01 11:19:072011新春纪念徽章
日期:2011-01-04 10:37:10ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15ITPUB 11周年纪念徽章
日期:2012-10-09 18:06:202013年新春福章
日期:2013-02-25 14:51:24
72#
发表于 2008-10-7 10:39 | 只看该作者
这个题目,太简单了,我刚毕业第一年,什么都不懂的时候,就用PLSQL写了一个。

使用道具 举报

回复
论坛徽章:
4
茶鸡蛋
日期:2011-11-21 15:51:37ITPUB 11周年纪念徽章
日期:2012-10-09 18:09:192013年新春福章
日期:2013-02-25 14:51:24灰彻蛋
日期:2013-06-24 13:26:37
73#
发表于 2008-10-9 22:06 | 只看该作者
看不懂哦
很强大

使用道具 举报

回复
论坛徽章:
1
授权会员
日期:2008-10-09 17:11:23
74#
发表于 2008-10-10 10:37 | 只看该作者
declare   @t   table(id   int   identity,num   decimal(10,2))  
  insert   @t   select   @a   union   all   select   @b   union   all   select   @c   union   all   select   @d  
   
  declare   @result   table(str1   varchar(100),str2   varchar(100),result   decimal(10,6))  
  insert   @result   select   rtrim(id)+'#'+rtrim(cast(num   as   int)),rtrim(cast(num   as   int)),num   from   @t  
   
  declare   @i   int  
  set   @i=1  
  while   @i<4  
  begin  
  insert   @result   select   distinct   A.str1+'+'+rtrim(id)+'#'+rtrim(cast(num   as   int)),A.str2+'+'+rtrim(cast(num   as   int)),result+num   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0   
  /*  
  and   not   exists   (select   1   from   @result   where   str2=A.str2+'+'+rtrim(cast(B.num   as   int)))  
  and   not   exists   (select   1   from   @result   where   str2=rtrim(cast(num   as   int))+'+'+A.str2   )  
  */  
  insert   @result   select   distinct   A.str1+'-'+rtrim(id)+'#'+rtrim(cast(num   as   int)),A.str2+'-'+rtrim(cast(num   as   int)),result-num   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0  
     
  insert   @result   select   distinct   case   when   charindex('-',str2)>0   
                                                        then     rtrim(id)+'#'+rtrim(cast(num   as   int))+'-('+A.str1+')'  
                                                        else   rtrim(id)+'#'+rtrim(cast(num   as   int))+'-'+A.str1  
                                                        end,  
                                              case   when   charindex('-',str2)>0   
                                                        then   rtrim(cast(num   as   int))+'-('+A.str2+')'  
                                                        else   rtrim(cast(num   as   int))+'-'+A.str2  
                                                        end  
  ,num-result   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0  
   
  insert   @result   select   distinct   
        case   when   charindex('+',A.str1)>0   or   charindex('-',A.str1)>0   
                  then   '('+A.str1+')*'+rtrim(id)+'#'+rtrim(cast(num   as   int))  
                  else     A.str1+'*'+rtrim(id)+'#'+rtrim(cast(num   as   int))   
                  end,  
        case   when   charindex('+',A.str2)>0   or   charindex('-',A.str2)>0      
                  then   '('+A.str2+')*'+rtrim(cast(num   as   int))  
                  else   A.str2+'*'+rtrim(cast(num   as   int))  
                  end,  
  result*num   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0  
  /*  
  and   not   exists   (select   1   from   @result   where   str2=(case   when   charindex('+',A.str2)>0   or   charindex('-',A.str2)>0      
                  then   '('+A.str2+')*'+rtrim(cast(B.num   as   int))  
                  else   A.str2+'*'+rtrim(cast(B.num   as   int))  
                  end))   
  and   not   exists   (select   1   from   @result   where   str2=(case   when   charindex('+',A.str2)>0   or   charindex('-',A.str2)>0      
                  then   rtrim(cast(B.num   as   int))+'*('+A.str2+')'  
                  else   rtrim(cast(B.num   as   int))+'*'+A.str2  
                  end)   )  
  */  
  insert   @result   select   distinct   
        case   when   (charindex('+',A.str1)>0   or   charindex('-',A.str1)>0)   and   charindex('(',str1)=0   
                  then   '('+A.str1+')/'+rtrim(id)+'#'+rtrim(cast(num   as   int))  
                  else     A.str1+'/'+rtrim(id)+'#'+rtrim(cast(num   as   int))   
                  end,  
        case   when   charindex('+',A.str2)>0   or   charindex('-',A.str2)>0     and   charindex('(',str2)=0      
                  then   '('+A.str2+')/'+rtrim(cast(num   as   int))  
                  else   A.str2+'/'+rtrim(cast(num   as   int))  
                  end,  
  result/num   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0   and   num<>0  
   
  insert   @result   select   distinct   
        case   when   (charindex('+',A.str1)>0   or   charindex('-',A.str1)>0)   and   charindex('(',str1)=0   
                  then   rtrim(id)+'#'+rtrim(cast(num   as   int))+'/('+A.str1+')'  
                  else   rtrim(id)+'#'+rtrim(cast(num   as   int))+'/'+A.str1  
                  end,  
        case   when   ((charindex('+',A.str2)>0   or   charindex('-',A.str2)>0)     and   charindex('(',str2)=0)   or   charindex('/',str2)>0   or   charindex('*',str2)>0  
                  then   rtrim(cast(num   as   int))+'/('+A.str2+')'  
                  else   rtrim(cast(num   as   int))+'/'+A.str2  
                  end,  
  num/result   from   @result   A,@t   B   where   charindex(rtrim(id)+'#'+rtrim(cast(num   as   int)),str1)=0   and   result<>0  
   
  set   @i=@i+1  
  end  
  --select   cast(rtrim(str2)   as   varchar(20))   计算公式   from   @result   order   by   cast(rtrim(str2)   as   varchar(20))  
   
  select   distinct   cast(rtrim(str2)   as   varchar(20))   计算公式   from   @result   where     result=24   and   len(str2)-len(replace(replace(replace(replace(str2,'+',''),'-',''),'*',''),'/',''))=3

使用道具 举报

回复
论坛徽章:
46
凯迪拉克
日期:2013-08-22 10:00:10Jeep
日期:2013-08-10 07:21:13ITPUB社区12周年站庆徽章
日期:2013-10-08 14:57:28ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB 11周年纪念徽章
日期:2012-10-09 18:05:07奥运会纪念徽章:体操
日期:2008-10-24 13:08:31会员2007贡献徽章
日期:2007-09-26 18:42:10马上加薪
日期:2014-04-11 09:34:11秀才
日期:2015-09-06 10:19:32
75#
发表于 2008-10-13 15:30 | 只看该作者
太难了,这是算法的题目。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
76#
 楼主| 发表于 2008-10-17 03:02 | 只看该作者


用自定义函数求值使得SQL简短一些:

CREATE OR REPLACE FUNCTION f_op (p_n1 NUMBER, p_op VARCHAR2, p_n2 NUMBER) RETURN NUMBER
AS
BEGIN
   RETURN CASE WHEN p_op = '+' THEN p_n1 + p_n2
               WHEN p_op = '-' THEN p_n1 - p_n2
               WHEN p_op = '*' THEN p_n1 * p_n2
               WHEN p_op = '/' AND p_n2<>0 THEN p_n1 / p_n2
               ELSE NULL
          END;

END f_op;
/


WITH vw_tmp AS (
     SELECT a.n  as a
           ,o1.o as o1
           ,b.n  as b
           ,o2.o as o2
           ,c.n  as c
           ,o3.o as o3
           ,d.n  as d
       from t24 a, t24 b,t24 c,t24 d,o24 o1,o24 o2,o24 o3
      WHERE a.rowid NOT IN (b.rowid,c.rowid,d.rowid)
            AND b.rowid NOT IN (c.rowid,d.rowid)
            AND c.rowid<>d.rowid
     )
    ,vw_tmp2 AS (       ---- ((a b) c) d
    SELECT '(('||a||o1||b||')'||o2||c||')'||o3||d as formula
          ,f_op(f_op(f_op(a,o1,b),o2,c),o3,d) result
     FROM vw_tmp
    UNION ALL     ---- (a (b c)) d
    SELECT '('||a||o1||'('||b||o2||c||'))'||o3||d as formula
          ,f_op(f_op(a,o1,f_op(b,o2,c)),o3,d) as result
     FROM vw_tmp
    UNION ALL ---- (a b) (c d)
    SELECT '('||a||o1||b||')'||o2||'('||c||o3||d||')' as formula
          ,f_op(f_op(a,o1,b),o2,f_op(c,o3,d)) as result
     FROM vw_tmp
    UNION ALL  ---- a ((b c) d)
    SELECT a||o1||'(('||b||o2||c||')'||o3||d||')' as formula
          ,f_op(a,o1,f_op(f_op(b,o2,c),o3,d)) as result
     FROM vw_tmp
    UNION ALL ---- a (b (c d))
    SELECT a||o1||'('||b||o2||'('||c||o3||d||'))' as formula
          ,f_op(a,o1,f_op(b,o2,f_op(c,o3,d))) as result
     FROM vw_tmp
   )
SELECT formula,result FROM vw_tmp2
WHERE result=24;
/




WITH v24 AS (SELECT id,n,MAX(SYS_CONNECT_BY_PATH(n,',')) OVER() as sorted
                   ,REGEXP_REPLACE(MAX(SYS_CONNECT_BY_PATH(n,',')) OVER(),'[^,]+','',1,id) AS sorted_ex
               FROM (SELECT ROWNUM id, n FROM (SELECT * FROM t24 ORDER BY n))
              START WITH id=1 CONNECT BY id=PRIOR id+1
             )
    ,vw_tmp AS (
     SELECT a.n  as a
           ,o1.o as o1
           ,b.n  as b
           ,o2.o as o2
           ,c.n  as c
           ,o3.o as o3
           ,d.n  as d
           ,a.sorted
           ,a.sorted_ex as a_ex
           ,d.sorted_ex as d_ex
           ,o1.o||o2.o||o3.o as op
           ,DECODE(o1.o,'+',1,'-',1,2) AS p1
           ,DECODE(o2.o,'+',1,'-',1,2) AS p2
           ,DECODE(o3.o,'+',1,'-',1,2) AS p3
       from v24 a, v24 b,v24 c,v24 d,o24 o1,o24 o2,o24 o3
      WHERE a.id NOT IN (b.id,c.id,d.id)
            AND b.id NOT IN (c.id,d.id)
            AND c.id<>d.id
     )
    ,vw_tmp2 AS (  ---- ((a b) c) d
    SELECT CASE WHEN p2<p3 THEN '(' END
           ||CASE WHEN p1<p2 THEN '(' END
           ||CASE WHEN op IN ('***','+++') THEN REGEXP_SUBSTR(sorted,'[^,]',1,1)
                  WHEN o1||o2 IN ('**','++') THEN REGEXP_SUBSTR(d_ex,'[^,]',1,1)
                  WHEN o1 IN ('*','+') THEN TO_CHAR(LEAST(a,b))
                  ELSE TO_CHAR(a)
             END
           ||o1
           ||CASE WHEN op IN ('***','+++') THEN REGEXP_SUBSTR(sorted,'[^,]',1,2)
                  WHEN o1||o2 IN ('**','++') THEN REGEXP_SUBSTR(d_ex,'[^,]',1,2)
                  WHEN o1 IN ('*','+') THEN TO_CHAR(GREATEST(a,b))
                  ELSE TO_CHAR(b)
             END
           ||CASE WHEN p1<p2 THEN ')' END
           ||o2
           ||CASE WHEN op IN ('***','+++') THEN REGEXP_SUBSTR(sorted,'[^,]',1,3)
                  WHEN o1||o2 IN ('**','++') THEN REGEXP_SUBSTR(d_ex,'[^,]',1,3)
                  ELSE TO_CHAR(c)
             END
           ||CASE WHEN p2<p3 THEN ')' END
           ||o3
           ||CASE WHEN op IN ('***','+++') THEN REGEXP_SUBSTR(sorted,'[^,]',1,4)
                  ELSE TO_CHAR(d)
             END
           as formula
          ,f_op(f_op(f_op(a,o1,b),o2,c),o3,d) result
     FROM vw_tmp
    UNION ALL    ---- (a (b c)) d
    SELECT CASE WHEN p1<p3 THEN '(' END
           ||a
           ||o1
           ||CASE WHEN p2<p1 OR p2=p1 AND o1 IN ('/','-') THEN '(' END
           ||CASE WHEN o2 IN ('*','+') THEN LEAST(b,c)
                  ELSE b
             END
           ||o2
           ||CASE WHEN o2 IN ('*','+') THEN GREATEST(b,c)
                  ELSE c
             END
           ||CASE WHEN p2<p1 OR p2=p1 AND o1 IN ('/','-') THEN ')' END
           ||CASE WHEN p1<p3 THEN ')' END
           ||o3
           ||d as formula
          ,f_op(f_op(a,o1,f_op(b,o2,c)),o3,d) as result
     FROM vw_tmp
    WHERE o1 NOT IN ('*','+')        -- 如果'*','+'则与((a b) c) d等价
    UNION ALL   ---- a ((b c) d)
    SELECT a
           ||o1
           ||CASE WHEN p3<p1 OR p3=p1 AND o1 IN ('/','-') THEN '(' END
           ||CASE WHEN p2<p3 THEN '(' END
           ||CASE WHEN o2||o3 IN ('**','++') THEN REGEXP_SUBSTR(a_ex,'[^,]',1,1)
                  WHEN o2 IN ('*','+') THEN TO_CHAR(LEAST(b,c))
                  ELSE TO_CHAR(b)
             END
           ||o2
           ||CASE WHEN o2||o3 IN ('**','++') THEN REGEXP_SUBSTR(a_ex,'[^,]',1,2)
                  WHEN o2 IN ('*','+') THEN TO_CHAR(GREATEST(b,c))
                  ELSE TO_CHAR(c)
             END
           ||CASE WHEN p2<p3 THEN ')' END
           ||o3
           ||CASE WHEN o2||o3 IN ('**','++') THEN REGEXP_SUBSTR(a_ex,'[^,]',1,3)
                  ELSE TO_CHAR(d)
             END
           ||CASE WHEN p3<p1 OR p3=p1 AND o1 IN ('/','-') THEN ')' END
           as formula
          ,f_op(a,o1,f_op(f_op(b,o2,c),o3,d)) as result
     FROM vw_tmp
    WHERE o1 NOT IN ('*','+') -- 如果'*','+'则与((a b) c) d等价
    UNION ALL  ---- a (b (c d))
    SELECT a
           ||o1
           ||CASE WHEN p2<p1 OR p2=p1 AND o1 IN ('/','-') THEN '(' END
           ||b
           ||o2
           ||CASE WHEN p3<p2 OR p2=p3 AND o2 IN ('/','-') THEN '(' END
           ||CASE WHEN o3 IN ('*','+') THEN LEAST(c,d)
                  ELSE c
             END
           ||o3
           ||CASE WHEN o3 IN ('*','+') THEN GREATEST(c,d)
                  ELSE d
             END
           ||CASE WHEN p3<p2 OR p2=p3 AND o2 IN ('/','-') THEN ')' END
           ||CASE WHEN p2<p1 OR p2=p1 AND o1 IN ('/','-') THEN ')' END
           as formula
          ,f_op(a,o1,f_op(b,o2,f_op(c,o3,d))) as result
     FROM vw_tmp
    WHERE o1 NOT IN ('*','+') AND o2 NOT IN ('*','+')  -- 如果 o1='*','+'则与(a (b c)) d等价,如果 o2='*','+'则与a ((b c) d)等价
    UNION ALL    ---- (a b) (c d)
    SELECT CASE WHEN p1<p2 THEN '(' END
           ||CASE WHEN op IN ('+*+','*+*') THEN REGEXP_SUBSTR(sorted,'[^,]',1,1) --排序
                  WHEN o1 IN ('*','+') THEN TO_CHAR(LEAST(a,b))
                  ELSE TO_CHAR(a)
             END
           ||o1
           ||CASE WHEN op IN ('+*+','*+*') THEN REGEXP_SUBSTR(sorted,'[^,]',1,2)
                  WHEN o1 IN ('*','+') THEN TO_CHAR(GREATEST(a,b))
                  ELSE TO_CHAR(b)
             END
           ||CASE WHEN p1<p2 THEN ')' END
           ||o2
           ||CASE WHEN p3<p2 OR p2=p3 AND o2 IN ('/','-') THEN '(' END
           ||CASE WHEN op IN ('+*+','*+*') THEN REGEXP_SUBSTR(sorted,'[^,]',1,3)
                  WHEN o3 IN ('*','+') THEN TO_CHAR(LEAST(c,d))
                  ELSE TO_CHAR(c)
             END
           ||o3
           ||CASE WHEN op IN ('+*+','*+*') THEN REGEXP_SUBSTR(sorted,'[^,]',1,4)
                  WHEN o3 IN ('*','+') THEN TO_CHAR(GREATEST(c,d))
                  ELSE TO_CHAR(d)
             END
           ||CASE WHEN p3<p2 OR p2=p3 AND o2 IN ('/','-') THEN ')' END
           as formula
          ,f_op(f_op(a,o1,b),o2,f_op(c,o3,d)) as result
     FROM vw_tmp
    WHERE NOT (p1=p2 OR p2=p3 AND o2 IN ('+','*')) AND op<>'+*-'         ---  op='+*-' 等价于  op='-*+'
   )
SELECT DISTINCT formula FROM vw_tmp2
WHERE result=24;



使用道具 举报

回复
论坛徽章:
0
77#
发表于 2008-10-17 17:27 | 只看该作者
不错,学习了。

使用道具 举报

回复
论坛徽章:
14
授权会员
日期:2007-10-28 17:13:06祖国60周年纪念徽章
日期:2009-10-09 08:28:00生肖徽章2007版:羊
日期:2009-09-10 11:27:42生肖徽章2007版:鼠
日期:2009-03-10 21:32:40生肖徽章2007版:马
日期:2009-03-10 21:28:53生肖徽章2007版:牛
日期:2009-03-10 21:19:32生肖徽章2007版:羊
日期:2009-03-10 21:16:04奥运会纪念徽章:铁人三项
日期:2008-10-24 13:27:21生肖徽章2007版:鸡
日期:2008-10-18 21:30:18数据库板块每日发贴之星
日期:2008-10-13 01:02:26
78#
发表于 2008-10-18 22:18 | 只看该作者
太复杂了,SQL有点费解

使用道具 举报

回复
论坛徽章:
14
itpub13周年纪念徽章
日期:2014-10-08 15:19:03itpub13周年纪念徽章
日期:2014-10-08 15:19:03itpub13周年纪念徽章
日期:2014-10-08 15:19:03itpub13周年纪念徽章
日期:2014-10-08 15:19:03授权会员
日期:2006-03-10 17:20:13itpub13周年纪念徽章
日期:2014-10-08 15:19:03itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-09-26 11:35:50优秀写手
日期:2014-09-04 06:00:03马上有车
日期:2014-02-18 16:41:11
79#
发表于 2008-10-21 16:04 | 只看该作者
太强了,顶一个,学习中。。。

使用道具 举报

回复
论坛徽章:
18
生肖徽章2007版:虎
日期:2008-04-11 18:37:24奥运会纪念徽章:击剑
日期:2008-07-03 11:38:17迷宫蛋
日期:2011-05-10 13:03:40茶鸡蛋
日期:2011-05-10 13:05:16蜘蛛蛋
日期:2011-05-10 13:07:01灰彻蛋
日期:2012-12-10 11:47:16鲜花蛋
日期:2013-07-07 10:07:20
80#
发表于 2008-10-24 16:08 | 只看该作者
嗯, 这个贴得留个名

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表