背包算法

本文介绍了一种使用SQL实现特定金额组合查找的方法。通过按位运算和递归查询,从数据库表中找出所有能组合成指定金额(如10元)的记录。此方法适用于解决财务或商品组合等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下两个算法均是为了解决我前篇博客上的那个问题的高级方法
但效率有待进一步提高

create table t_money(id int primary key,amount int not null);

insert into t_money values(1,2);
insert into t_money values(2,2);
insert into t_money values(3,3);
insert into t_money values(4,5);
insert into t_money values(5,2);
insert into t_money values(6,8);
insert into t_money values(7,1);
insert into t_money values(8,2);
insert into t_money values(9,2);
insert into t_money values(10,3);

select * from t_money;

+----+--------+
| id | amount |
+----+--------+


1 2
2 2
3 3
4 5
5 2
6 8
7 1
8 2
9 2
10 3

--按位运算
declare
type test_t is table of t_money%rowtype index by binary_integer;
res test_t;
l_row binary_integer:=1;
sums number;
cal varchar2(1000);
seq varchar2(1000);

begin

SELECT *
BULK COLLECT INTO res
FROM t_money;

--dbms_output.put_line(res.count);
for i in res.first .. 2**res.last-1 loop
sums:=0;
seq:='';
cal:='';
for j in res.first .. i loop -- 不会比i更大
if (bitand(i,2**(j-1)) <> 0) then -- 如果不改为j-1, 当总额为31(全选)时解不出来
sums:=sums+res(j).amount;
cal:=cal||res(j).amount||'+';
seq:=seq||res(j).id||',';
IF SUMS >= 10 THEN ---- 尽早退出
EXIT;
END IF;
end if;
end loop;
if (sums=10) then
cal:=substr(cal,1,length(cal)-1);
seq:=substr(seq,1,length(seq)-1);
dbms_output.put_line('结果是:'||cal||'='||sums);
dbms_output.put_line('序列是:'||seq);
exit;
end if;
end loop;
end;


--分支
select path
from (select rownum rn,
hierarchy.sys_connect_by_path(level, id, ',') path,
hierarchy.sys_sum_by_path(level, amount) amount
from t_money
connect by id > prior id
AND hierarchy.sys_sum_by_path(level, amount)<=10 --- 中途裁剪
)
where amount = 10;

----
create or replace package hierarchy is
type strtabletype1 is table of varchar2(4000) index by binary_integer;
type strtabletype is table of strtabletype1 index by binary_integer;

strtable strtabletype;

type numtabletype1 is table of number index by binary_integer;
type numtabletype is table of numtabletype1 index by binary_integer;

numtable numtabletype;
function sys_connect_by_path(p_level in number,
p_value in varchar2,
p_delimiter in varchar2 default ',',
p_index IN NUMBER DEFAULT 1)
return varchar2;
function sys_sum_by_path(p_level in number, p_value in number,p_index IN NUMBER DEFAULT 1)
return number;
pragma restrict_references(sys_connect_by_path, wnds);
pragma restrict_references(sys_sum_by_path, wnds);
end;

---

create or replace package body hierarchy is
ls_ret varchar2(4000);
ln_ret number;
function sys_connect_by_path(p_level in number,
p_value in varchar2,
p_delimiter in varchar2 default ',',
p_index IN NUMBER DEFAULT 1)
return varchar2 is
begin
strtable(p_index)(p_level) := p_value;
ls_ret := p_value;
for i in reverse 1 .. p_level - 1 loop
ls_ret := strtable(p_index)(i) || p_delimiter || ls_ret;
end loop;
return ls_ret;
end;

function sys_sum_by_path(p_level in number, p_value in number,p_index IN NUMBER DEFAULT 1)
return number is
begin
numtable(p_index)(p_level) := p_value;
ln_ret := p_value;
for i in reverse 1 .. p_level - 1 loop
ln_ret := numtable(p_index)(i) + ln_ret;
end loop;
return ln_ret;
end;
end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值