楼主: newkid

[精华] 趣味SQL:微软面试题:过河

[复制链接]
论坛徽章:
3
ITPUB十周年纪念徽章
日期:2011-11-01 16:24:51蜘蛛蛋
日期:2012-04-19 16:07:402013年新春福章
日期:2013-02-25 14:51:24
61#
发表于 2012-3-30 09:24 | 只看该作者
newkid 发表于 2012-3-29 21:08
可恶的人肉!把我们动脑筋的乐趣都剥夺了。
即使这样,用SQL实现这个算法也是不错的练习题!

额,sorry,我看大家说的跟这个差不多了,所以就发了。。
我下次注意。

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
62#
 楼主| 发表于 2012-3-30 21:47 | 只看该作者
changhe325 发表于 2012-3-30 09:24
额,sorry,我看大家说的跟这个差不多了,所以就发了。。
我下次注意。

你注意到我60楼说的现象了吗?应该怎么修改?
两人的用这个算法真是无比威猛。

使用道具 举报

回复
求职 : 数据库开发
论坛徽章:
10
茶鸡蛋
日期:2012-04-19 16:08:35美羊羊
日期:2015-03-24 15:03:142015年新春福章
日期:2015-03-06 11:58:392015年新春福章
日期:2015-03-04 14:53:16马上有对象
日期:2014-08-15 13:23:54优秀写手
日期:2014-08-15 06:00:13马上加薪
日期:2014-08-14 22:48:12马上有房
日期:2014-09-04 07:54:53ITPUB 11周年纪念徽章
日期:2012-10-09 18:14:482015年新春福章
日期:2015-03-30 14:49:43
63#
发表于 2012-3-31 00:59 | 只看该作者
本帖最后由 jixch 于 2012-3-31 09:15 编辑

写了个M个人最多N个人同时过桥的判断逻辑.3个多小时的成果啊....,如下:
M个人,每次最多N个人过桥
过桥的时间从小到大依次为 T1T2T3T4T5、……、Tm
第一次过桥判断:
判断M - N是否小于N-1
M - N < N - 1
第一次过河:过桥时间最小的 M – N + 1 个人过河 时间为TM-N+1
返回:河对面(已经过河的)的 过桥时间最短的返回 时间为 T1
第二次过河:(剩下人数为: M-(M–N+1)+1 = N)没过河的N个人一次过河 时间为Tm            ------结束
M – N >= N - 1
         第一次过河:过桥时间最小的N个人过河 时间为 Tn
         返回:河对面(已经过河的)的 过桥时间最短的返回 T1
         第二次过河:过桥时间最大的N个人过河 时间为 Tm
       返回:河对面(已经过河的)的 过桥时间最短的返回 T2
       第三次过河判断:(设此时还没过河的人数为M1 = M-2N+2
       判断 M1 - N N - 1 的大小关系
                   M1 – N < N - 1
                            第三次过河:M1人中的最小的M1 – N + 1人过河
                            返回:河对面(已经过河的)的 过桥时间最短的返回 时间为T1
                            第四次过河:剩余人数为:M1-(M1-N+1)+1 = N,没过河的一起过河 时间为Tm      ------------结束
                   M1-N = N-1
                            设剩下的人的过河时间从小到大依次为T1T2、……Tn-1Tn、……、Tm1
                            此时河对面的(已经过河的)人群中过桥时间最短的返回 时间为T3
                            判断Tn + T1 + Tm1 Tm1 + T3 + max(Tn-1,T3) 的大小关系
                            Tn + T1 + Tm1 >= Tm1 + T3 + max(Tn-1,T3)
                                     第三次过河:M1个人中时间最大的N个人(Tn、……、Tm1)过河
                                     返回:河对面(已经过河的)的 过桥时间最短的返回 时间为T3
                                     第四次过河:剩余人数为:M1–N+1 = N,没过河的一起过河            ------------结束
                            Tn + T1 + Tm1 < Tm1 + T3 + max(Tn-1,T3)
                                     第三次过河:M1个人中时间最小的N个人(T1、……、Tn)过河
                                     返回:河对面(已经过河的)的 过桥时间最短的返回 时间为T3
                                     第四次过河:剩余人数为:M1–N+1 = N,没过河的一起过河           ------------结束
                   M1-N > N-1
                            第三次过河:M1个人中时间最小的N个人过河
                            返回:河对面(已经过河的)的 过桥时间最短的返回 时间为T1
                      第四次过河:没有过河的剩下人中过桥时间最大的N个人过河 时间为 Tm1
                      返回:河对面(已经过河的)的 过桥时间最短的返回
                            后面 重新执行第三次过河和第四次过河

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
64#
 楼主| 发表于 2012-3-31 01:43 | 只看该作者
楼上的很威武!这个算法有论证过程吗?

如果要用一个SQL来实现,我觉得会很困难,这也是乐趣所在。

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
65#
发表于 2012-3-31 02:14 | 只看该作者
本帖最后由 guostong 于 2012-3-30 13:38 编辑

桥的容量可以更改:

column name format a10;
column name_BACK format a10;
column name_HIST format a20;
var num number; -- bridge capability
exec :num := 3;

with
t_accessory (totalsteps, cnt, md) as
(
   select ceil((count(1)-1)/(:num-1)) + ceil((count(1)-1)/(:num-1)) - 1 totalsteps, count(1) cnt, mod(count(1)-1,2) md from bridge_crossing
),
t_positions (name, time, ps, od) as
(
  select name, time, power(2,row_number() over (order by name) -1) ps,
    rank() over (order by time) od
    from bridge_crossing
),
t_combinations ( name, ps, p_ps, time, step ) as
(
  select name, ps, ps, time, 1 step from t_positions
  union all
  select t.name || b.name, t.ps + b.ps, b.ps, greatest(t.time, b.time), step + 1
  from t_combinations t, t_positions b
  where b.ps > t.p_ps and t.step < :num
),
steps (name, ps, name_hist, name_back, ps_back, time, step) as
(
   -- step 1
   select name,ps, name, '', 0, time, 1
    from t_combinations where step = :num
   union all
   select
      case when mod(s.step,2) = 1 then replace(s.name, c.name)
           else s.name || c.name
      end name,
      case when mod(s.step,2) = 1 then s.ps - c.ps
           else s.ps + c.ps
      end ps,
      s.name_hist || c.name,
      case when mod(s.step,2) = 1 then s.name_back || c.name
           else s.name_back
      end name_back,
      case when mod(s.step,2) = 1 then c.ps
           else 0
      end ps_back,
      s.time + c.time, s.step + 1
    from steps s, t_combinations c, t_accessory a
    where s.step < a.totalsteps
    -- back
    and (
          (mod(s.step,2) = 1 and bitand(s.ps, c.ps) > 0 and c.step = 1)
    -- forward
          or
          (mod(s.step,2) = 0 and bitand(s.ps, c.ps) = 0
           and(
                (a.totalsteps > s.step + 1 or a.totalsteps = s.step + 1 and a.md = 0 ) and c.step = :num
                or
                 a.totalsteps = s.step + 1 and a.md <> 0 and c.step < :num
                  and s.ps + c.ps = power(2, cnt) - 1
               )
          )
        )
)
select * from
(
  select steps.*, row_number() over (order by steps.time) od from steps, t_accessory t
  where step = t.totalsteps order by time
) where od <= 10;

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
66#
发表于 2012-3-31 02:17 | 只看该作者
本帖最后由 guostong 于 2012-3-30 13:28 编辑

有点问题,只对3个人同时过桥工作,正在检查

更正了。

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期: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
67#
 楼主| 发表于 2012-3-31 02:38 | 只看该作者
呵呵,你终于也用BITMAP了,和我的思路基本上一样,只不过我最后一批(不满N人)是拿到递归结束后来做;你的返回部分也没有优化(最快的人返回)。

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
68#
发表于 2012-3-31 02:43 | 只看该作者
本帖最后由 guostong 于 2012-3-30 14:02 编辑
newkid 发表于 2012-3-30 13:38
呵呵,你终于也用BITMAP了,和我的思路基本上一样,只不过我最后一批(不满N人)是拿到递归结束后来做;你的 ...

加上回送的限制性能会好些
我的sql对2个人不工作了,正在查

2有点特殊,楼下更正了

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
69#
发表于 2012-3-31 02:48 | 只看该作者
本帖最后由 guostong 于 2012-3-30 13:59 编辑

加了回送的限制:

column name format a10;
column name_BACK format a10;
column name_HIST format a20;

var num number;
exec :num := 3;

with
t_accessory (totalsteps, cnt, md) as
(
   select ceil((count(1)-1)/(:num-1)) + ceil((count(1)-1)/(:num-1)) - 1 totalsteps, count(1) cnt, mod(count(1)-1,2) md from bridge_crossing
),
t_positions (name, time, ps, od) as
(
  select name, time, power(2,row_number() over (order by name) -1) ps,
    rank() over (order by time) od
    from bridge_crossing
),
t_combinations ( name, ps, p_ps, time, step, od ) as
(
  select name, ps, ps, time, 1 step, od from t_positions
  union all
  select t.name || b.name, t.ps + b.ps, b.ps, greatest(t.time, b.time), step + 1, t.od
  from t_combinations t, t_positions b
  where b.ps > t.p_ps and t.step < :num
),
steps (name, ps, name_hist, name_back, ps_back, time, step) as
(
   -- step 1
   select name,ps, name, '', 0, time, 1
    from t_combinations where step = :num
   union all
   select
      case when mod(s.step,2) = 1 then replace(s.name, c.name)
           else s.name || c.name
      end name,
      case when mod(s.step,2) = 1 then s.ps - c.ps
           else s.ps + c.ps
      end ps,
      s.name_hist || c.name,
      case when mod(s.step,2) = 1 then s.name_back || c.name
           else s.name_back
      end name_back,
      case when mod(s.step,2) = 1 then c.ps
           else 0
      end ps_back,
      s.time + c.time, s.step + 1
    from steps s, t_combinations c, t_accessory a
    where s.step < a.totalsteps
    -- back
    and (
          (mod(s.step,2) = 1 and bitand(s.ps, c.ps) > 0 and c.step = 1 and c.od <= :num)
    -- forward
          or
          (mod(s.step,2) = 0 and bitand(s.ps, c.ps) = 0
           and(
                (a.totalsteps > s.step + 1 or a.totalsteps = s.step + 1 and a.md = 0 ) and c.step = :num
                or
                 a.totalsteps = s.step + 1 and a.md <> 0 and c.step < case when :num=2 then 3 else :num end
                and s.ps + c.ps = power(2, cnt) - 1
               )
          )
        )
)
select * from
(
  select steps.*, row_number() over (order by steps.time) od from steps, t_accessory t
  where step = t.totalsteps order by time
) where od <= 10;

使用道具 举报

回复
论坛徽章:
38
授权会员
日期:2005-10-30 17:05:332012新春纪念徽章
日期:2012-02-13 15:12:09现任管理团队成员
日期:2011-11-07 09:46:59ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41ITPUB9周年纪念徽章
日期:2010-10-08 09:31:21版主3段
日期:2012-05-15 15:24:112009新春纪念徽章
日期:2009-01-04 14:52:282010新春纪念徽章
日期:2010-03-01 11:06:202009日食纪念
日期:2009-07-22 09:30:00祖国60周年纪念徽章
日期:2009-10-09 08:28:00
70#
发表于 2012-3-31 03:06 | 只看该作者
本帖最后由 guostong 于 2012-3-30 14:08 编辑
newkid 发表于 2012-3-30 13:38
呵呵,你终于也用BITMAP了,和我的思路基本上一样,只不过我最后一批(不满N人)是拿到递归结束后来做;你的 ...

bitmap 是个好东西
你的代码什么时候贴出来?

使用道具 举报

回复

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

本版积分规则 发表回复

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