本期题目:
2011年度itpub数据库技术大会将于4月15日隆重举行。与会人员分布于不同城市(A,B,C,D,....),每个城市及其会员人数保存在一张表cities(city_name, members)
这些城市及他们之间的通路构成了一张网络交通图。有直接通路的两个城市及其距离保存在表routes之中,所有通路都是双向的,但每条直接通路只用一行记录来表示。
外地的会员将乘坐出租车参加大会,车费等于距离*价格(常数)。本地会员不用考虑交通费。
交通费定义:itpub要为外地会员发放往返的交通补贴,每人每公里2元(双程),在哪个城市举办能够最节省,需要花费多少钱?
问题:选择在哪个城市举行,能够使得会员的总交通费最低?列出这个城市及应发放给其他城市会员的总的交通补助。
输出格式如下:
输出3列数据,按城市名升序排列
举办城市 TOTAL 总费用
举办城市 来自城市 费用
....
例如,假设你求出在A城市最省,总的补助需要发放10000元,其中给B城市的会员要发8000, 给C城市的会员要发2000
输出
CODE:
A TOTAL 10000
A B 8000
A C 2000
如果存在在多个城市办会交通费用相同,则都列出,按城市名升序排列
例如,假设你求出在A,B城市最省,需要发10000元,如果在A办,B城市的会员8000, C城市的会员2000,如果在B办,A城市的会员8000, C城市的会员2000,
输出
CODE:
A TOTAL 10000
A B 8000
A C 2000
B TOTAL 10000
B A 8000
B C 2000
表结构和样例数据如下,样例数据供参考,评委将用多组数据验证你的解答。表结构不能变动,不按此表结构答题的不得分。
CODE:
CREATE TABLE cities (
city_name VARCHAR2(10) PRIMARY KEY
,members NUMBER
);
INSERT INTO cities
(
SELECT A ,20 FROM dual union
SELECT B ,31 FROM dual union
SELECT C ,23 FROM dual union
SELECT D ,42 FROM dual union
SELECT E ,25 FROM dual union
SELECT F ,29 FROM dual union
SELECT G ,32 FROM dual union
SELECT H ,45 FROM dual union
SELECT I ,50 FROM dual union
SELECT J ,32 FROM dual union
SELECT K ,22 FROM dual
);
commit;
CREATE TABLE routes (
city1 VARCHAR2(10)
,city2 VARCHAR2(10)
,distance NUMBER
,PRIMARY KEY (city1,city2)
,CONSTRAINT check_cities CHECK (city1
INSERT INTO routes
(
SELECT A ,B , 71 FROM dual union
SELECT A ,C , 80 FROM dual union
SELECT A ,D , 80 FROM dual union
SELECT A ,E , 66 FROM dual union
SELECT A ,F , 86 FROM dual union
SELECT C ,G ,112 FROM dual union
SELECT D ,G , 60 FROM dual union
SELECT G ,H ,102 FROM dual union
SELECT G ,I , 91 FROM dual union
SELECT G ,J ,133 FROM dual union
SELECT G ,K ,127 FROM dual union
SELECT C ,D , 79 FROM dual union
SELECT C ,H ,155 FROM dual union
SELECT C ,E ,119 FROM dual union
SELECT B ,D , 52 FROM dual union
SELECT D ,I , 44 FROM dual union
SELECT B ,L , 41 FROM dual union
SELECT J ,L ,201 FROM dual union
SELECT B ,F , 79 FROM dual union
SELECT H ,K , 38 FROM dual union
SELECT J ,K , 81 FROM dual
);
commit;
数据库平台:适用Oracle、MS SQL Server,版本(Oracle推荐10gr2(包含)以上版本、MS SQL Sever推荐2008版本)
提交的答案:
/*
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)这个子句用于分组统计总成本及各城市间成本。
*/
with allroutes as (select rownum rn,city1,city2,distance from routes
union all select rownum rn,city2,city1,distance from routes),
s(rn,root,city2,sum_dis,path) as(
select rn,city1 root,city2,DISTANCE sum_dis,city1||-||city2 path from allroutes
union all
select a.rn,s.root,a.city2,s.sum_dis+a.DISTANCE sum_dis,s.path||-||a.city2 path
from s,allroutes a
where a.city1=s.city2 and instr(s.path,a.city2)<=0
and 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)
)
)
cycle rn set cycle_flag to Y de