ITPUB论坛-中国最专业的IT技术社区

 找回密码
 注册
查看: 45912|回复: 47

[精华] 受lastwinner邀请,尝试作答第三届SQL大赛第一道题

[复制链接]
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2016-1-12 21:21 | 显示全部楼层 |阅读模式
本帖最后由 rollingpig 于 2016-1-12 22:45 编辑

Insert - 255168 row(s), executed in 37.773 sec.

思路都在注释中
  1. insert /*+append*/ into TICTACTOE
  2. with winbin as --列举8种赢的可能性的二进制表示,分别是三种独占一行,三种独占一列,两种对角线
  3. (select (4+2+1)*8*8 b1, (4+2+1)*8 b2, (4+2+1)*1 b3, --独占一行
  4.         (64+8+1)*4 b4, (64+8+1)*2 b5, (64+8+1)*1 b6, -- 独占一列
  5.         64*1+8*2+1*4 b7, 64*4+8*2+ 1*1 b8  --对角线
  6. from dual),
  7. p as (select --9个格子
  8. level num,  --第几个格子的10进制
  9. power(2,level-1) bin, --第几个格子的二进制
  10. power(10,9-level) str  --第几个格子的字符位
  11. from dual connect by level <10),
  12. X(nums,  --十进制表示
  13. bins, --二进制表示
  14. strs, -- 字符位
  15. len, --长度(本方第几个子)
  16. won --是否已经赢了(同时match winbin中的位置)
  17. ) as (
  18. select num,bin,str,1,0 from p --第一个开始
  19. union all
  20. select num+nums*100 --十进制表示,注意,由于各下一个,本方的下一个等于全局的下两个
  21. ,bin+bins --二进制
  22. ,str+strs --字符位置
  23.   ,len+1 --本方第几个子
  24. ,(case when bitand(bin+bins,b1)=b1  --注意binand用法, 如果已下子的二进制存在赢得3个位置,就证明本方赢了
  25.         or  bitand(bin+bins,b2)=b2
  26.         or  bitand(bin+bins,b3)=b3
  27.         or  bitand(bin+bins,b4)=b4
  28.         or  bitand(bin+bins,b5)=b5
  29.         or  bitand(bin+bins,b6)=b6
  30.         or  bitand(bin+bins,b7)=b7
  31.         or  bitand(bin+bins,b8)=b8
  32.   then 1  
  33.    else 0
  34. end)
  35.   from p,X,winbin
  36.   where X.won=0 --如果上个结果串赢了,就不必再下
  37.   and len<5 --最多5个
  38.   and bitand(bins,bin)=0 --不能重复下同一位置,注意bitand用法
  39.   )
  40.    select X.nums+O.nums*10 moves  -- 第二个人的需要移一位,相加,结果就是两个人下的结果
  41.      ,translate(X.strs+2*O.strs,'012','-XO') board --把第二个人的位置*2, 相加,得到012的位置串,用translate,把012分别改为 -,X,O
  42.      ,decode(X.won,1,'X',decode(O.won,1,'O','D')) as winner --这个简单,两个decode嵌套,case when可能跟好看
  43.      --, X.nums,O.nums
  44.     from X,X O --X是第一个人,O是第二个人
  45.      where
  46.       bitand(X.bins,O.bins)=0 --注意bitand, 这里表示没有重复下同一个格子
  47.       and (
  48.      (X.len in(5) and O.len in(4)  and O.won=0 ) --下到9个,当然,第二个人显然不能赢
  49.      or (X.len in(3,4) and O.len in(2,3) and X.len=O.len+1 and X.won=1 and O.won=0) --第一个人赢,下到
  50.      or (X.len in(3,4) and O.len in(3,4) and X.len=O.len and X.won=0 and O.won=1) --第二个人赢
  51.      )
复制代码
论坛徽章:
399
优秀写手
日期:2013-12-18 09:29:08itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-10-01 15:27:22itpub13周年纪念徽章
日期:2014-10-09 12:04:18马上有钱
日期:2014-10-14 21:37:37马上有钱
日期:2015-01-22 00:39:13喜羊羊
日期:2015-02-20 22:26:07懒羊羊
日期:2015-02-21 22:03:31懒羊羊
日期:2015-03-04 14:52:112015年新春福章
日期:2015-03-06 11:58:18
发表于 2016-1-12 21:34 | 显示全部楼层
老猪风采依旧

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2016-1-12 21:35 | 显示全部楼层
本帖最后由 rollingpig 于 2016-1-12 22:46 编辑

第二个,没有本质区别。
  1. --insert /*+append*/ into TICTACTOE
  2. select count(*) from(
  3. with p as (select --9个格子
  4. level num,  --第几个格子的10进制
  5. power(2,level-1) bin, --第几个格子的二进制
  6. power(10,9-level) str  --第几个格子的字符位
  7. from dual connect by level <10),
  8. X(nums,  --十进制表示
  9. bins, --二进制表示
  10. strs, -- 字符位
  11. len, --长度(本方第几个子)
  12. won --是否已经赢了(同时match winbin中的位置)
  13. ) as (
  14. select num,bin,str,1,0 from p --第一个开始
  15. union all
  16. select num+nums*100 --十进制表示,注意,由于各下一个,本方的下一个等于全局的下两个
  17. ,bin+bins --二进制
  18. ,str+strs --字符位置
  19.   ,len+1 --本方第几个子
  20. ,(case when  --注意binand用法, 如果已下子的二进制存在赢得3个位置,就证明本方赢了
  21.             bitand(bin+bins,7*64)=7*64  --第一行
  22.         or  bitand(bin+bins,7*8)=7*8  --第二行
  23.         or  bitand(bin+bins,7)=7  --第三行
  24.         or  bitand(bin+bins,73*4)=73*4 --第一列
  25.         or  bitand(bin+bins,73*2)=73*2 --第二列
  26.         or  bitand(bin+bins,73)=73 --第三列
  27.         or  bitand(bin+bins,64+8*2+1*4)=64+8*2+1*4 --左上右下对角线
  28.         or  bitand(bin+bins,64*4+8*2+1)=64*4+8*2+1 --左下右上对角线
  29.   then 1  
  30.    else 0
  31. end)
  32.   from p,X
  33.   where X.won=0 --如果上个结果串赢了,就不必再下
  34.   and len<5 --最多5个
  35.   and bitand(bins,bin)=0 --不能重复下同一位置,注意bitand用法
  36.   )
  37.    --create table dmp as
  38.    select X.nums+O.nums*10 moves  -- 第二个人的需要移一位,相加,结果就是两个人下的结果
  39.      ,translate(lpad(X.strs+2*O.strs,9,0),'012','-XO') board --把第二个人的位置*2, 相加,得到012的位置串,用translate,把012分别改为 -,X,O
复制代码

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2016-1-12 22:18 | 显示全部楼层
本帖最后由 rollingpig 于 2016-1-12 22:47 编辑

无注释版
  1. with CELL as (select level M,  power(2,level-1) B, power(10,9-level) P from dual connect by level <10),
  2. MOVE(MV,  BI,  PO,  RD,  WON  ) as (
  3. select M,B,P,1,0 from CELL
  4. union all
  5. select M+MV*100  ,B+BI ,P+PO,RD+1
  6. ,(case when bitand(B+BI,7*64)=7*64 or  bitand(B+BI,7*8)=7*8   or bitand(B+BI,7)=7  
  7.         or   bitand(B+BI,73*4)=73*4 or  bitand(B+BI,73*2)=73*2 or bitand(B+BI,73)=73
  8.         or   bitand(B+BI,64+8*2+1*4)=64+8*2+1*4  or bitand(B+BI,64*4+8*2+1)=64*4+8*2+1
  9.   then 1    else 0 end)
  10.   from CELL C,MOVE M  where WON=0 and RD<5 and bitand(BI,B)=0 )
  11. select X.MV+O.MV*10 moves,translate(lpad(X.PO+2*O.PO,9,0),'012','-XO') board  ,decode(X.WON,1,'X',decode(O.WON,'O','D')) as winner
  12.     from MOVE X,MOVE O
  13.     where bitand(X.BI,O.BI)=0 and (
  14.         (X.RD in(3,4) and O.RD in(2,3) and X.RD=O.RD+1 and X.WON=1 and O.WON=0)
  15.      or (X.RD in(3,4) and O.RD in(3,4) and X.RD=O.RD   and X.WON=0 and O.WON=1)
  16.      or (X.RD =5 and O.RD =4 and O.WON=0) )
复制代码

使用道具 举报

回复
论坛徽章:
496
目光如炬
日期:2015-11-22 22:00:00秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21秀才
日期:2016-01-06 14:10:21探花
日期:2016-01-06 14:11:18进士
日期:2016-01-06 14:11:18
发表于 2016-1-12 22:19 | 显示全部楼层
有意思,先生成一个人的下法再拼成两个人的棋局,这种思路第一次见到。
老猪肯定没玩过瘾,请移步:
http://www.itpub.net/thread-2050490-1-2.html

使用道具 举报

回复
论坛徽章:
399
优秀写手
日期:2013-12-18 09:29:08itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-10-01 15:27:22itpub13周年纪念徽章
日期:2014-10-09 12:04:18马上有钱
日期:2014-10-14 21:37:37马上有钱
日期:2015-01-22 00:39:13喜羊羊
日期:2015-02-20 22:26:07懒羊羊
日期:2015-02-21 22:03:31懒羊羊
日期:2015-03-04 14:52:112015年新春福章
日期:2015-03-06 11:58:18
发表于 2016-1-12 22:41 | 显示全部楼层
newkid 发表于 2016-1-12 22:19
有意思,先生成一个人的下法再拼成两个人的棋局,这种思路第一次见到。
老猪肯定没玩过瘾,请移步:
http ...

可惜剪枝在最后一步

使用道具 举报

回复
论坛徽章:
288
秀才
日期:2017-03-02 10:30:47布鲁克
日期:2016-10-08 10:06:50秀才
日期:2016-09-27 15:16:21秀才
日期:2016-09-27 15:11:30奥运会纪念徽章:自行车
日期:2016-09-26 15:54:59举人
日期:2016-06-24 09:25:21秀才
日期:2016-06-24 09:21:04双鱼座
日期:2016-06-15 17:14:38射手座
日期:2016-05-26 14:02:50白羊座
日期:2016-05-23 11:49:19
发表于 2016-1-12 22:47 | 显示全部楼层
  欢迎常来逛逛!

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2016-1-12 22:48 | 显示全部楼层
前面也有剪的。

这次没追求性能,主要追求写起来代码漂亮

使用道具 举报

回复
认证徽章
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
发表于 2016-1-12 23:06 | 显示全部楼层
重看了一下,发现之前代码两处错误,第二个decode少了参数,translate里面的原始字符串忘了前面补0. 还是老了。

使用道具 举报

回复
论坛徽章:
10000
地主之星
日期:2015-07-20 17:15:36地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-10-15 16:56:19地主之星
日期:2015-09-01 17:59:09地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-09-01 14:14:25地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58地主之星
日期:2015-08-31 16:17:58
发表于 2016-1-13 00:28 | 显示全部楼层

使用道具 举报

回复

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

本版积分规则

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