SQL遞歸遊戲

SQL遞歸遊戲-你厲害嗎,來過5關 收藏 此文於2010-07-28被推薦到CSDN首頁
如何被推薦?
5個flash的遊戲地址是
http://www.sostart.com/article/view.php/765
此類遊戲一般都是通過窮舉或者遞歸之類的方法來求解,對於編成語言來說都比較簡單。
這裏用SQL語言的CTE遞歸來玩玩看。我的算法和答案如下:

 

/*
    四個字段分別代表 羊,狼,草,人的位置,0表示河左邊,1表示河右邊。
    每次都必須有人過河,因爲動物和植物們都不會划船。
*/
declare @t table (y bit , l bit , c bit , r bit , path varchar (8000 ))
insert into @t select 0 , 0 , 0 , 0 , ''

;with t
as
(
    select * , 0 as cc from @t union all
    select ~ y , l , c , ~ r , path + '人羊' + ltrim (r )+ '→' , cc + 1 from t where cc < 10 and y = r and y & l & c = 0 and path not like '%人羊_→' union all
    select y , ~ l , c , ~ r , path + '人狼' + ltrim (r )+ '→' , cc + 1 from t where cc < 10 and   l = r and y & l & c = 0 and y <> c and path not like '%人狼_→' union all
    select y , l , ~ c , ~ r , path + '人草' + ltrim (r )+ '→' , cc + 1 from t where   cc < 10 and c = r and y & l & c = 0 and y <> l and path not like '%人草_→' union all
    select y , l , c , ~ r , path + '人' + ltrim (r )+ '→' , cc + 1 from t where cc < 10 and   y & l & c = 0 and y <> c and y <> l and path not like '%人_→'
   
)
select REPLACE (REPLACE (path , '0' , '過河' ), '1' , '返回' ) as path from t where y & l & c = 1

/*
人羊過河→人返回→人草過河→人羊返回→人狼過河→人返回→人羊過河→
人羊過河→人返回→人狼過河→人羊返回→人草過河→人返回→人羊過河→
*/
 

 

/*

    前五個字段分別代表 左人數,左鬼數,右人數,右鬼數,船位置
    船位置爲代表在右邊,代表在左邊
    當右邊沒有人和鬼時(gr+pr>0),不執行返回操作,遞歸結束
*/
;with t (pl , gl , pr , gr , boat , path )
as
(
    select 0 , 0 , 3 , 3 , cast (0 as bit ), cast ('' as varchar (8000 )) union all
    select pl + 2 as pl , gl , pr - 2 as pr , gr , ~ boat , path + '2人過河→'
        from t where boat = 0 and pr >= 2 and (pr - 2 >= gr or pr = 2 ) union all
    select pl + 1 , gl + 1 , pr - 1 , gr - 1 , ~ boat , path + '1人鬼過河→'
        from t where boat = 0 and pr >= 1 and gr >= 1 and pl >= gl   union all
    select pl , gl + 2 , pr , gr - 2 , ~ boat , path + '2鬼過河→'
        from t where boat = 0 and gr >= 2 and (pl - 2 >= gl or pl = 0 ) union all
    select pl - 1 , gl , pr + 1 , gr , ~ boat , path + '1人返回→'
        from t where boat = 1 and pl >= 1 and gr + pr > 0   and (pl - 1 >= gl or pl = 1 ) and pr + 1 >= gr union all
    select pl , gl - 1 , pr , gr + 1 , ~ boat , path + '1鬼返回→'
        from t where boat = 1 and gl >= 1 and gr + pr > 0 and (pr - 1 >= gr or pr = 0 )  union all
    select pl - 1 , gl - 1 , pr + 1 , gr + 1 , ~ boat , path + '1人鬼返回→'
        from t where boat = 1 and pl >= 1 and gl >= 1 and gr + pr > 0 and pr >= gr and path not like '%1人鬼過河→'
)
select path from t where pr = 0 and gr = 0

/*
2鬼過河→鬼返回→鬼過河→鬼返回→人過河→人鬼返回→人過河→鬼返回→鬼過河→鬼返回→鬼過河→
2鬼過河→鬼返回→鬼過河→鬼返回→人過河→人鬼返回→人過河→鬼返回→鬼過河→人返回→人鬼過河→
1人鬼過河→人返回→鬼過河→鬼返回→人過河→人鬼返回→人過河→鬼返回→鬼過河→鬼返回→鬼過河→
1人鬼過河→人返回→鬼過河→鬼返回→人過河→人鬼返回→人過河→鬼返回→鬼過河→人返回→人鬼過河→
*/

 

/*
第三關:一家人過河

結果:過河的全部組合有萬多中情況,其中滿足s之內的有種方法

關聯的三個表a b c配合charindex函數分別可以表示出可以過河的兩個人和可以返回的一個人
當沒有人可以過河則遞歸自動結束
遞歸中的case語句可以表示當對岸有個人的時候就不需要返回
*/

declare @t table (name varchar (8000 ), time int )

insert into @t
select '瘦人' , 1 union
select '小胖' , 3 union
select '姑娘' , 6 union
select '大胖' , 8 union
select '瘸子' , 12

;with t (forword_name , time , path ) as (

    select   replace (a . name + b. name , c . name , '' ), b. time + c . time , a . name + b. name + '過河→' + c . name + '返回→'
        from @t a , @t b, @t c   where a . time < b. time and charindex (c . name , a . name + b. name )> 0
       
    union all
   
    select  
        case when len (forword_name )< 6 then replace (forword_name + a . name + b. name , c . name , '' ) else forword_name + a . name + b. name end ,
        case when len (forword_name )< 6 then t . time + b. time + c . time else t . time + b. time end ,
        case when len (forword_name )< 6 then path + a . name + b. name + '過河→' + c . name + '返回→' else path + a . name + b. name + '過河→' end
        from @t a , @t b, @t c , t   where a . time < b. time and charindex (c . name , forword_name + a . name + b. name )> 0
        and charindex (a . name , t . forword_name )= 0 and charindex (b. name , t . forword_name )= 0
   )
  select path , time from t where len (forword_name )= 10   and time <= 30
/*
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人小胖過河→瘦人返回→瘦人姑娘過河→
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人小胖過河→瘦人返回→瘦人姑娘過河→
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人小胖過河→瘦人返回→瘦人姑娘過河→
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人小胖過河→瘦人返回→瘦人姑娘過河→
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人小胖過河→瘦人返回→瘦人姑娘過河→
瘦人小胖過河→小胖返回→大胖瘸子過河→瘦人返回→瘦人姑娘過河→瘦人返回→瘦人小胖過河→
...共40行
*/

 

 

/*第四關:跳馬
*/

declare @t table (p varchar (max ), x int , y int )
insert into @t
select 'p11' , 1 , 1 union
select 'p12' , 1 , 2 union
select 'p13' , 1 , 3 union
select 'p14' , 1 , 4 union
select 'p21' , 2 , 1 union
select 'p22' , 2 , 2 union
select 'p23' , 2 , 3 union
select 'p24' , 2 , 4 union
select 'p31' , 3 , 1 union
select 'p32' , 3 , 2 union
select 'p33' , 3 , 3 union
select 'p34' , 3 , 4 union
select 'p42' , 4 , 2 union
select 'p43' , 4 , 3

;with t (pstart , p, c , x , y ) as
(
    select   p, p, 1 , x , y from @t
        union all
    select t . pstart , t . p+ '→' + t_next . p, c + 1 , t_next . x , t_next . y from @t t_next , t where
        (
            (abs (t_next . x - t . x )= 1 and abs (t_next . y - t . y )= 2 ) or
            (abs (t_next . x - t . x )= 2 and abs (t_next . y - t . y )= 1 ) )
            and (CHARINDEX (t_next . p, t . p)= 0 or (c = 14 and t_next . p= t . pstart ))
)
select p from t   where c = 15

/*
p43→p31→p23→p11→p32→p13→p21→p42→p34→p22→p14→p33→p12→p24→p43
p43→p31→p12→p33→p14→p22→p34→p13→p21→p42→p23→p11→p32→p24→p43
p43→p31→p12→p24→p32→p11→p23→p42→p34→p13→p21→p33→p14→p22→p43
p43→p24→p32→p11→p23→p42→p21→p13→p34→p22→p14→p33→p12→p31→p43
...共112行
*/

 

;with t as (
    select 17 as f1 , 26 as f2 , 20 as f3 , 19 as f4 , 31 as f5 , cast ('' as   varchar (8000 )) as path
        union all select f1 + 8 , f2 + 8 , f3 , f4 , f5 , path + '12上→' from t where f1 < 21 and f2 < 21
        union all select f1 + 8 , f2 , f3 + 8 , f4 , f5 , path + '13上→' from t where f1 < 21 and f3 < 21
        union all select f1 + 8 , f2 , f3 , f4 + 8 , f5 , path + '14上→' from t where f1 < 21 and f4 < 21
        union all select f1 + 8 , f2 , f3 , f4 , f5 + 8 , path + '15上→' from t where f1 < 21 and f5 < 21
        union all select f1 , f2 + 8 , f3 + 8 , f4 , f5 , path + '23上→' from t where f2 < 21 and f2 < 21
        union all select f1 , f2 + 8 , f3 , f4 + 8 , f5 , path + '24上→' from t where f2 < 21 and f4 < 21
        union all select f1 , f2 + 8 , f3 , f4 , f5 + 8 , path + '25上→' from t where f2 < 21 and f5 < 21
        union all select f1 , f2 , f3 + 8 , f4 + 8 , f5 , path + '34上→' from t where f3 < 21 and f4 < 21
        union all select f1 , f2 , f3 + 8 , f4 , f5 + 8 , path + '35上→' from t where f3 < 21 and f5 < 21
        union all select f1 , f2 , f3 , f4 + 8 , f5 + 8 , path + '45上→' from t where f4 < 21 and f5 < 21
        union all select f1 - 13 , f2 - 13 , f3 , f4 , f5 , path + '12下→' from t where f1 > 25 and f2 > 25
        union all select f1 - 13 , f2 , f3 - 13 , f4 , f5 , path + '13下→' from t where f1 > 25 and f3 > 25
        union all select f1 - 13 , f2 , f3 , f4 - 13 , f5 , path + '14下→' from t where f1 > 25 and f4 > 25
        union all select f1 - 13 , f2 , f3 , f4 , f5 - 13 , path + '15下→' from t where f1 > 25 and f5 > 25
        union all select f1 , f2 - 13 , f3 - 13 , f4 , f5 , path + '23下→' from t where f2 > 25 and f2 > 25
        union all select f1 , f2 - 13 , f3 , f4 - 13 , f5 , path + '24下→' from t where f2 > 25 and f4 > 25
        union all select f1 , f2 - 13 , f3 , f4 , f5 - 13 , path + '25下→' from t where f2 > 25 and f5 > 25
        union all select f1 , f2 , f3 - 13 , f4 - 13 , f5 , path + '34下→' from t where f3 > 25 and f4 > 25
        union all select f1 , f2 , f3 - 13 , f4 , f5 - 13 , path + '35下→' from t where f3 > 25 and f5 > 25
        union all select f1 , f2 , f3 , f4 - 13 , f5 - 13 , path + '45下→' from t where f4 > 25 and f5 > 25
       
        union all select f1 + 8 , f2 + 8 , f3 , f4 , f5 , path + '12上→' from t where f1 < 21 and f2 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 + 8 , f2 , f3 + 8 , f4 , f5 , path + '13上→' from t where f1 < 21 and f3 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 + 8 , f2 , f3 , f4 + 8 , f5 , path + '14上→' from t where f1 < 21 and f4 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 + 8 , f2 , f3 , f4 , f5 + 8 , path + '15上→' from t where f1 < 21 and f5 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 + 8 , f3 + 8 , f4 , f5 , path + '23上→' from t where f2 < 21 and f2 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 + 8 , f3 , f4 + 8 , f5 , path + '24上→' from t where f2 < 21 and f4 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 + 8 , f3 , f4 , f5 + 8 , path + '25上→' from t where f2 < 21 and f5 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 , f3 + 8 , f4 + 8 , f5 , path + '34上→' from t where f3 < 21 and f4 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 , f3 + 8 , f4 , f5 + 8 , path + '35上→' from t where f3 < 21 and f5 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
        union all select f1 , f2 , f3 , f4 + 8 , f5 + 8 , path + '45上→' from t where f4 < 21 and f5 < 23 and f3 between 21 and 25 and f4 between 21 and 25 and f5 between 21 and 25
)

select path from t
where f1 between 21 and 25
and f2 between 21 and 25
and f3 between 21 and 25
and f4 between 21 and 25
and f5 between 21 and 25

/*
34上→45下→45上→35下→35上→15上→25下→25上→
34上→45下→45上→35下→35上→14上→24下→24上→
34上→35下→35上→45下→45上→15上→25下→25上→
34上→35下→35上→45下→45上→14上→24下→24上→
*/

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jinjazz/archive/2010/07/28/5770919.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章