第一屆SQL大賽第一期優秀解題思路彙總
SQL大賽第一期解題方法的公佈,讓我領略了各種新穎巧妙的解題方法。精神也為之一振,就決定寫篇總結,把大家好的方法記下來。
第一期題目大意如下:
給定一個5×5的矩陣,要求:
1、每行不得超過兩個球;
2、每列不得超過兩個球;
3、每個45度斜線不得超過兩個球(包括左傾斜和右傾斜,及對角線)
問:這樣的擺法有多少種。
解答要求:
以單個SQL語句實現。
通用性(比如說,可擴充套件到三個球四個球,或者6階矩陣等)
效率。也就是執行時間。
其他要求就不一一敘述了。
按照以上這個題目及要求,大家都給出了各式奇思妙想。下面是所有答題結果中,我認為比較有代表性或創造性的思路的彙總,並不包含全部的解題方法。其中有些解題過程很長,或者都還沒格式化,比較亂,看得我比較眼痠(由此可見,評委要全部仔細的看完更是辛苦啊!),都沒仔細看。
其中IR的得分很高,我也特意留意了下他的解題方法,不過他用的遞迴with需要在11g環境下執行,但是看newkid的分析感覺挺不錯的。以後有環境再分析下。
這個題目主要要解決的是兩個方面的問題:基礎資料的構造和斜線的相加
一、基礎資料構造
***************************************************************
1、遞迴法(這是我自己的方法(GO),所以先拿出來曬曬)
***************************************************************
這個方法利用了connect by構造資料的特性,首先構造出基礎資料:5個0和2個1.
SQL> select floor(rownum/(dim + cnt - 1)) n, rownum r, dim
2 from dual, (select 5 dim, length('11') cnt from dual) dims
3 connect by rownum <= dim+cnt
4 /
N R DIM
---------- ---------- ----------
0 1 5
.................
0 5 5
1 6 5
1 7 5
7 rows selected
構造這個資料的目的是可以透過R列,來實現不同遞迴層次的關聯而得到不同組合的01字串。但是這個方法有個缺陷,就是隻能侷限於5+2模式(即5×5矩陣,每行最多兩個球的模式),這個newkid也提到了。所以在第二個的解答中我已經將這個方法擴充套件了:
SQL> with
2 dims as(select 5 dim, 2 cnt from dual)
3 select decode(sign(rownum-dim),1,1,0) n, rownum r, dim
4 from dual, dims
5 connect by rownum <= dim+cnt
6 /
N R DIM
---------- ---------- ----------
0 1 5
...................
0 5 5
1 6 5
1 7 5
7 rows selected
這樣就不再侷限於5+2,而是適用於任意情況的組合了,根據情況只要修改相應的數值即可:
SQL> with
2 dims as(select 6 dim, 2 cnt from dual)
3 select decode(sign(rownum-dim),1,1,0) n, rownum r, dim
4 from dual, dims
5 connect by rownum <= dim+cnt
6 /
N R DIM
---------- ---------- ----------
0 1 6
..................
0 6 6
1 7 6
1 8 6
8 rows selected
構造了這個基本資料後,我們就可以再套一層層次查詢,把這些不同組合的字串取出來:
SQL> with
2 dims as(select 5 dim, 2 cnt from dual),
3 nums as(
4 select n, to_number(substr(n, 1, 1)) n1,
5 to_number(substr(n, 2, 1)) n2, to_number(substr(n, 3, 1)) n3,
6 to_number(substr(n, 4, 1)) n4, to_number(substr(n, 5, 1)) n5
7 from (select distinct replace(sys_connect_by_path(n, ','), ',') n
8 from (select decode(sign(rownum-dim),1,1,0) n, rownum r, dim
9 from dual, dims
10 connect by rownum <= dim+cnt)
11 where level = dim
12 connect by nocycle prior r <> r and level <= dim))
13 select * from nums
14 /
N N1 N2 N3 N4 N5
----------- ---------- ---------- ---------- ---------- ----------
00001 0 0 0 0 1
.................................
10001 1 0 0 0 1
11000 1 1 0 0 0
16 rows selected
***************************************************************
2、逐個遞推法
***************************************************************
這個是LL的方法。說實話,LL的方法很巧妙,要我我怎麼也想不到那裡去。我覺得跟他得的得分一樣有點慚愧,呵呵。他的思路有點類似於我們人的推理,先在第一個位置固定放1,然後在其後的每個位置上向右逐個移動的放1,得到四種情況。
然後在第二個位置固定放1,而後在其後的位置上再逐個移動的放1.依次類推,便得到了10組。但是這個得有個前提,即必須是得事先確定,所有行都是兩個球,否則的話還少了0個和1個球的6中情況。這個是它的不足之處。
【程式碼】:
SQL> with t1 as
2 (
3 select iid, x, y, x + y + 25 z1, x - y z2
4 from (select rownum iid, mod(rownum - 1, 5) + 1 x, ceil(rownum / 5) y
5 from dual
6 connect by rownum <= 25)
7 )
8 select x,y,substr('00000', 1, y - 1) || '1' ||
9 substr('00000', y, x - y - 1) || '1' ||
10 substr('00000', x, 5 - x) rr
11 from t1
12 where x > y
13 and x != y
14 /
X Y RR
---------- ---------- --------------------------------
2 1 11000
.........
5 3 00101
5 4 00011
10 rows selected
***************************************************************
3、排列組合法
***************************************************************
這個方法的思路有點類似於我們學機率論時的思路,我想,CA和VL學機率論學的比較好,所以想問題的出發點也是基於機率的。首先,我們知道,5×5的矩陣,每個位置只有0和1兩種可能,所以5×5的矩陣,只要將每個位置的兩種可能性用笛卡爾積乘起來,就能得到所有的擺法了。不過,寫的有點冗長了。
【程式碼】
(select 0 v11 from dual union all select 1 from dual) a1,
.................
(select 0 v55 from dual union all select 1 from dual) a25
這個可以先用一個with子句構造一個tmp表,然後在from用引用即可。
其中,TK和JJ用的也是類似的方法。不過他們是首先得到一行的所有擺法。然後再擴充套件到5行的所有擺法。比CA簡潔很多。
【程式碼】
SQL> with c as
2 (select rownum - 1 c from dual connect by rownum <= 2)
3 select to_number (c1.c || c2.c || c3.c || c4.c || c5.c) line
4 from c c1, c c2, c c3, c c4, c c5
5 where c1.c + c2.c + c3.c + c4.c + c5.c = 2
6 order by 1 desc
7 /
LINE
----------
11000
.....
101
11
10 rows selected
***************************************************************
4、二進位制構造(想不出好的名字,就這麼命名了)
***************************************************************
這個方法是先不管多少個球,反正每個位置兩種可能,總共有2^5=32種情況給全部列出來。列舉的方式很明顯是基於二進位制轉換的思路,即將0-31的每個數字都轉換為二進位制,就可得到這些不同組合的字串了。
【程式碼】
SQL> select col1 || col2 || col3 || col4 || col5 strings,
2 col1 + col2 + col3 + col4 + col5 balls,
3 r.*
4 from (select mod(floor(rownum / 16), 2) col1,
5 mod(floor(rownum / 8), 2) col2,
6 mod(floor(rownum / 4), 2) col3,
7 mod(floor(rownum / 2), 2) col4,
8 mod(floor(rownum), 2) col5
9 from dual
10 connect by rownum <= 32) r
11 where col1 + col2 + col3 + col4 + col5 <= 5
12 ORDER BY 1 desc
13 /
STRINGS BALLS COL1 COL2 COL3 COL4 COL5
------------ ---------- ---------- ---------- ---------- ---------- ----------
11111 5 1 1 1 1 1
..............
00001 1 0 0 0 0 1
00000 0 0 0 0 0 0
32 rows selected
以上列舉了構造資料的幾個主要演算法,其他的也基本上類似。
上面,我們完成了題目的第一個關鍵部分:資料構造。接下來就是斜線處理了。
二、斜線的判斷與處理
斜線處理思路更加新穎巧妙,主要那麼三類:
***************************************************************
1、座標點相加法(這個是我,也是其他很多人用的)
***************************************************************
這個稱謂看上去好像很了不起,但是實際上這是最土、最冗長、也是擴充套件性最差的辦法了。本法是基於最基本的5×5圖形的,在得到每個點的值後,將相應45度斜線的座標點加起來,就得到斜線和了。每條斜線都得這麼加,還得看清楚了別寫錯了就功虧一簣了。
【程式碼】
n15 + n24 + n33 + n42 + n51 <= 2 --對角線相加
n21 + n32 + n43 + n54 <= 2
n31 + n42 + n53 <= 2
n41 + n52 <= 2
n12 + n23 + n34 + n45 <= 2
n13 + n24 + n35 <= 2
n14 + n24 <= 2--右傾斜
n14 + n23 + n32 + n41 <= 2
n31 + n22 + n13 <= 2
n21 + n12 <= 2
n52 + n43 + n34 + n25 <= 2
n53 + n44 + n35 <= 2
n45 + n54 <= 2
***************************************************************
2、移位相加法
***************************************************************
這個方法灰常巧妙啊,包括TK和newkid用的都是這個。對此,我除了讚歎...........還是讚歎。TK僅用了17行就搞定了,而我用了43行。
言歸正傳,什麼是移位相加法呢?看下面的圖就明白了:
A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y
上面移位後:
A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y
第一列:U
第二列:P V
第三列:K Q W
第四列:F L R X
第五列:A G M S Y
第六列:B H N T
第七列:C I O
第八列:D J
第九列:E
仔細觀察一下,這些得到的列,不正是我們要取的斜線嘛。只要這些列作sum,就能得到我們想要的判斷了。
當然,別忘了右傾斜:
A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y
具體做法麼,只要給每行的數值乘以10的N倍(N為行號-1, 即=0...4)即可。
【程式碼】:
with c as
(select rownum - 1 c from dual connect by rownum <= 2),
lines as
(select to_number(c1.c || c2.c || c3.c || c4.c || c5.c) line
from c c1, c c2, c c3, c c4, c c5
where c1.c + c2.c + c3.c + c4.c + c5.c = 2
order by 1 desc)
select rownum, ltrim(to_char(line1.line, '09999')) ||
ltrim(to_char(line2.line, '09999')) ||
ltrim(to_char(line3.line, '09999')) ||
ltrim(to_char(line4.line, '09999')) ||
ltrim(to_char(line5.line, '00009')) result
from lines line1, lines line2, lines line3, lines line4, lines line5
where line1.line + line2.line + line3.line + line4.line + line5.line = 22222
and ltrim(to_char(line1.line + 10 * line2.line + 100 * line3.line + 1000 * line4.line + 10000 * line5.line), '012') is null
and ltrim(to_char(10000 * line1.line + 1000 * line2.line + 100 * line3.line + 10 * line4.line + line5.line), '012') is null;
這個解法的要求是每個位置的數值最大隻能是9,且斜線相加不能超過9。但是對於此題已經綽綽有餘了。
***************************************************************
3、等值分組法
***************************************************************
此法我只在LL這邊看到了,這是LL真正讓我感覺巧妙的地方。他首先列出了矩陣的所有座標點,然後對這些座標點標號。並且在給出每個座標點,橫座標和縱座標的差值。這個正是該法的精髓所在,它直接為後面的斜線相加做了鋪墊。接下來就是裁剪,去掉四個無需判斷的頂點,把這些斜線點變成行列成一個結果集。然後與構造的5+2組合進行笛卡爾積。再按照各個斜線點的座標標號到組合的字串中取出這些點,並對這些點相加,得到斜線相加的結果。然後取斜線最大點不大於2即可。
【程式碼】:
with t1 as
(--構造座標點,對座標點標號,並取每個座標點的橫豎座標差和和
select iid, x, y, x + y + 25 z1, x - y z2
from (select rownum iid, mod(rownum - 1, 5) + 1 x, ceil(rownum / 5) y
from dual
connect by rownum <= 25)
)
,t2 as (
--取出每條斜線座標點數大於2的集合
select iid, zz
from (select iid, z1 zz, count(*) over(partition by z1) cnt
from t1
union all
select iid, z2, count(*) over(partition by z2) cnt from t1)
where cnt > 2
)
,t3 as (--構造5+2
select rr,
to_number(substr(rr, 1, 1)) c1,
to_number(substr(rr, 2, 1)) c2,
to_number(substr(rr, 3, 1)) c3,
to_number(substr(rr, 4, 1)) c4,
to_number(substr(rr, 5, 1)) c5
from (select substr('00000', 1, y - 1) || '1' ||
substr('00000', y, x - y - 1) || '1' ||
substr('00000', x, 5 - x) rr
from t1
where x > y
and x != y)
)
select rownum, chr
from (select chr
from (select a.chr,
b.zz,
sum(to_number(substr(a.chr, b.iid, 1))) n1
from (select r1.rr || r2.rr || r3.rr || r4.rr || r5.rr chr
from t3 r1, t3 r2, t3 r3, t3 r4, t3 r5
where r1.c1 + r2.c1 + r3.c1 + r4.c1 + r5.c1 < 3
and r1.c2 + r2.c2 + r3.c2 + r4.c2 + r5.c2 < 3
and r1.c3 + r2.c3 + r3.c3 + r4.c3 + r5.c3 < 3
and r1.c4 + r2.c4 + r3.c4 + r4.c4 + r5.c4 < 3
and r1.c5 + r2.c5 + r3.c5 + r4.c5 + r5.c5 < 3) a,
t2 b
group by a.chr, b.zz)
group by chr
having max(n1) < 3
order by chr desc);
三、 總結
按道理,每次寫blog,都應該寫篇總結,尤其是這篇總結的總結。但是由於每次寫完blog,能夠一樣樣寫好並舉例,都感到很疲勞了,本身已經很不易,再寫個結論更累。呵呵,所以這次結論是在這篇原始版的blog寫完後幾天後才補充的。
說了這麼多,開始寫結論吧。
這次題目,主要思想是解決N×N矩陣中,球體擺放的問題。
面對的最主要問題是如何用只能生成行資料的一個SQL語句來解決二維的矩陣資料的生成和條件的判斷。
因此,我們很自然的把問題分解為兩個方面:
一、資料的生成
二、資料的判斷
資料的生成,我們又可以按如下思路來考慮:
首先,按照題目要求,是5×5的矩陣,且每行不得超過2個球,所以,每個行他的可能性只有:
C(5,2) +C(5,1) + 1 = 10 + 5 + 1 = 16種
也就是說,放兩個球有C(5,2)種可能性,放1個球有C(5,1)種可能性,沒有球,則只有一種可能性,加起來就是16種。
於是,我們得到了構造一行所需要的16種基本資料,其他行也是這個規則。於是總的可能性就有:
16^5 = 1048576種。
現在,我們要解決的就是如何從這100多萬種方案中篩選出題目所要求的矩陣了。於是,下一步的問題就變成了資料的判斷了。其實,資料的判斷雖然在方法上比資料的構造多種多樣,但是本質卻是一致的。就是判斷斜線的和不大於2。沿著這個思路,大家充分發揮了想象力,看到其他人尤其是幾位得分靠前的高手的答案後,我真是驚歎,大千世界,學無止境啊。
其中的對斜線分組法及移位相加法,是我很崇拜的方法,因為其擴充套件性和效率都很好,而且也很簡潔。這個是這次大賽值得我們學習的地方。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12932950/viewspace-689716/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ITPUB SQL大賽第一期SQL
- AngularJS 優秀文章彙總AngularJS
- JavaScript 中精度問題及解決思路彙總JavaScript
- 第十四屆藍橋杯第一期模擬賽 pythonPython
- 圖撲軟體榮獲第十一屆中國創新創業大賽全國賽優秀獎!創業
- sql大賽總結SQL
- 2020 KCTF秋季賽 | 第一題點評及解題思路
- BOT大賽計算機視覺賽題經驗分享:賽題詳解與思路分析計算機視覺
- “盛拓傳媒杯”SQL資料庫程式設計大賽第一期程式碼SQL資料庫程式設計
- 第一屆天池 PolarDB 資料庫效能大賽資料庫
- 優秀Python學習資源收集彙總Python
- 第二屆“演算法控”馬拉松程式設計競賽 解題思路演算法程式設計
- Google Flutter Clock 大賽優秀專案推薦GoFlutter
- Golang優秀開源專案彙總(持續更新。。。)Golang
- 22 個 Android Studio 優秀外掛彙總Android
- 藍橋杯歷年(省賽)試題彙總及試題詳解
- 綠盟科技入圍“2022年網路安全優秀創新成果大賽”優秀解決方案
- 2014第六屆華為程式設計大賽初賽第一輪程式設計
- 【獲獎】虎賁戰隊榮獲第二屆工業網際網路安全大賽優秀獎
- 第一屆C語言比賽答案C語言
- 第一屆PolarDB資料庫效能大賽Java選手分享資料庫Java
- 優秀的樹 - 題解(數學)
- MySQL 52個SQL效能優化策略SQL語句彙總MySql優化
- 看雪CTF.TSRC 2018 團隊賽 第一題 『初世紀』 解題思路
- java面試筆試題大彙總Java面試筆試
- 慢Sql優化思路SQL優化
- LeetCode 解題彙總LeetCode
- 第三屆華中地區邀請賽網路賽題解
- 入門大資料---大資料調優彙總大資料
- 螞蟻金服首屆ATEC開發者大賽人工智慧大賽圓滿落幕,一文詳解最佳解題方案人工智慧
- 2014第六屆華為創新杯程式設計大賽初賽解題報告程式設計
- 第一屆BMZCTF公開賽-WEB-WriteupWeb
- 隨身雲資料探勘競賽解題思路
- zabbix 小問題解決彙總
- Mysql 52條SQL語句效能優化策略彙總MySql優化
- 常用SQL技巧彙總SQL
- SQL字串操作彙總SQL字串
- sql每週彙總SQL