|
以前这里有过一些背包问题的讨论:
http://www.kz486.com/viewthread. ... ;extra=#pid14180585
http://www.kz486.com/thread-1291806-1-1.html
第二帖的原帖被缺德的楼主给删了,不过从我的回复还是可以看出一些有价值的东西。
回到楼主这个题,用暴力法玩了一下:
with d as (
---------- 每个物品用二进制一位表示,这是为了在求分组的时候,避免每个组合之间有重复的成员。ORACLE的NUMBER可以支持125位,就是小规模数据玩玩而已
select power(2,rownum) bit, datapath, bytes from testpath1
)
,grp(bits,bytes,last_bit,cnt) as (
------ 暴力法求出所有组合
select bit,bytes,bit,1 from d
union all
select grp.bits+d.bit,grp.bytes+d.bytes,d.bit,grp.cnt+1 from grp,d where grp.last_bit<d.bit and grp.bytes+d.bytes<=160000
)
,t(bits,cnt,last_bits,total_cnt,found,path,rn) as (
----- 开始拼凑这些组合,看看哪种拼法能够用最少的组凑齐所有物品
select bits,cnt,bits,(select count(*) from d),0,cast(bits as varchar2(1000)),1 from grp
union all
select t.bits+grp.bits,t.cnt+grp.cnt,grp.bits,t.total_cnt
,count(case when t.cnt+grp.cnt=t.total_cnt then 1 end) over()
,t.path||','||grp.bits
,row_number() over(partition by t.bits+grp.bits order by 1) rn ----- 这是一点点优化,如果组成员有互换的,其实不会影响最后总组数,所以只需留下一种
from t,grp
where t.bits<grp.bits and bitand(t.bits,grp.bits)=0 and t.cnt+grp.cnt<=t.total_cnt and t.found=0 and t.rn=1
)
,r as (
select to_number(regexp_substr(path,'[^,]+',1,level)) bit
,level grp_id
from (select * from t where cnt=total_cnt and rownum=1)
connect by level<=regexp_count(path,',')+1
)
select listagg(d.datapath,',') within group(order by d.datapath)
,sum(d.bytes)
from r,d
where bitand(r.bit,d.bit)>0
group by r.grp_id;
分组方法可能有很多,答案也不是**的,这是我这里跑出来的答案:
file0 149999
file3,file4,file5,file6 159996
file1,file7 15999 8
file2,file8,file9 152997
要为每组加上**的组号变成路径就很简单了, 这边没有写出来。
|
|