本期题目:
2011年度itpub数据库技术大会将于4月15日隆重举行。与会人员分布于不同城市(A,B,C,D,....),每个城市及其会员人数保存在一张表cities(city_name, members)
这些城市及他们之间的通路构成了一张网络交通图。有直接通路的两个城市及其距离保存在表routes之中,所有通路都是双向的,但每条直接通路只用一行记录来表示。
外地的会员将乘坐出租车参加大会,车费等于距离*价格(常数)。本地会员不用考虑交通费。
交通费定义:itpub要为外地会员发放往返的交通补贴,每人每公里2元(双程),在哪个城市举办能够最节省,需要花费多少钱?
问题:选择在哪个城市举行,能够使得会员的总交通费最低?列出这个城市及应发放给其他城市会员的总的交通补助。
输出格式如下:
输出3列数据,按城市名升序排列
举办城市 TOTAL 总费用
举办城市 来自城市 费用
....
例如,假设你求出在A城市最省,总的补助需要发放10000元,其中给B城市的会员要发8000, 给C城市的会员要发2000
输出
如果存在在多个城市办会交通费用相同,则都列出,按城市名升序排列
例如,假设你求出在A,B城市最省,需要发10000元,如果在A办,B城市的会员8000, C城市的会员2000,如果在B办,A城市的会员8000, C城市的会员2000,
输出
表结构和样例数据如下,样例数据供参考,评委将用多组数据验证你的解答。表结构不能变动,不按此表结构答题的不得分。
数据库平台:适用Oracle、MS SQL Server,版本(Oracle推荐10gr2(包含)以上版本、MS SQL Sever推荐2008版本)
原文见:http://www.itpub.net/thread-1408182-1-1.html
参赛者答案:http://www.itpub.net/thread-1415335-1-1.html
我提交的答案:
/*
Oracle11gR2,使用递归with语法,运行时间0.05秒
allroutes 根据routes得出包括反方向的所有路径组合,
s子句是生成各个城市间的不同路径列表:
rn的作用主要用于判断循环,
root表示出发城市,
city2表示目标城市,
sum_dis 表示距离,
path表示路径,里面的内容如'A-B-C-D'这样的
where条件中instr(s.path,a.city2)<=0作用是不出现回路,即当发现a.city2(新路径的终点城市)已经在上一路径列表里则退出这一支路的递归
s.sum_dis+a.DISTANCE<
(select nvl(max(r.DISTANCE),999999) from routes r
where (s.root=r.city1 and a.city2=r.city2) or (s.root=r.city2 and a.city2=r.city1)
)
上面这个条件是取消路径小于routes中直线路径长度的后续检测,这里没有使用前面定义的allroutes是为了使用索引进行性能优化
grouping sets(city_name,(city_name,city2)这个子句用于分组统计总成本及各城市间成本。
*/
/*
Oracle10gR2,使用connect by语法,运行时间0.3秒
allroutes 根据routes得出包括反方向的所有路径组合,
CONNECT_BY_ROOT(city1) root表示出发城市,
city2表示目标城市,
sum_money_str表示路径距离的一个字符串,里面的内容如'000+080+082+091'这样的,
nocycle 用于终止循环路径,
CONNECT_BY_ROOT(city1) <> city2 优化用,当路径回到根节点时退出,
+use_merge(a,b) 优化用
与子查询select rownum rn from dual connect by rownum < (select count(*) from cities) 关联,用于计算sum_money_str的值
sum(substr(a.sum_money_str, (b.rn) * 4 + 1, 3)) distance用于计算sum_money_str值
grouping sets(city_name,(city_name,city2)这个子句用于分组统计总成本及各城市间成本。
*/
以下是结果:
ROOT NVL(CITY_NAME,'TOTAL') SUM(MONEY)
---------- ---------------------- ----------
D TOTAL 68356
D A 3200
D B 3224
D C 3634
D E 7300
D F 7598
D G 3840
D H 14580
D I 4400
D J 12352
D K 8228
解题思路:见上面的备注。
评委点评:where (s.root=r.city1 and a.city2=r.city2) or (s.root=r.city2 and a.city2=r.city1))
条件的优化思路很明确。性能很好。
但是此答案也存在瑕疵,11g版本答案能正确输出多种选择和多次转乘,但一个城市的名称包含另外一个城市名称时无法输出正确结果。另:10g版本答案在某些测试数据下输出错误。
个人分析:
1、这道题主要是考一个图路径的算法,我算法不好,所以也不管理论的东西,按自己的理解去做。
2、因为看到前两期有许多人用11gR2新的with递归语法,所以也尝试学习一下。感觉功能比以前强大,不过语法规则设计得太差,估计是ORACLE公司新来的人设计,只是实现了功能,没考虑开发人员的思维习惯,所以不看参考手册基本上用不来。
3、题目好像是说要满足10gR2的版本,不清楚为什么用11gR2的新语法不扣分,反而加分,这不符合实际应用,毕竟实战中通用性很重要。
4、如评委所说,未考虑到城市名称中有字符名含的问题,原因是提供的测试数据不存在包含的现象,所以忽略了,实际当中还是存在的。
5、SQL整体性能还不错,但是大数据量时估计性能不好。
总体来说,这期得分还算合理,个人感觉第4名(3-7)很精彩,根据图论基础算法使用Oracle10g的MODEL语法解题。