背包问题是一道经典的组合优化问题,给定一组物品,每种物品都有本身的重量和价格,在限定的总重量内,如何选择使得物品的总价格最高,背包问题又能够分红01背包,彻底背包和多重背包等,网上关于这个问题的解答有不少,可是目前发现没有sql版本的,接下来我就为你们提供一下sql版本的解法,若是你们有更好的方法,欢迎评论。mysql
首先从最简单背包问题入手,给定背包的体积,每件物品只有一个,如何拿取物品能够填满背包
建立测试数据,vol表明物品的体积sql
CREATE TABLE `bag0` ( `vol` int(0) NULL DEFAULT NULL ); INSERT INTO `bag0` VALUES (17); INSERT INTO `bag0` VALUES (9); INSERT INTO `bag0` VALUES (14); INSERT INTO `bag0` VALUES (4); INSERT INTO `bag0` VALUES (16); INSERT INTO `bag0` VALUES (7); INSERT INTO `bag0` VALUES (18); INSERT INTO `bag0` VALUES (19); INSERT INTO `bag0` VALUES (5); INSERT INTO `bag0` VALUES (12);
解决这个问题的思路比较简单,因为每件物品只有一个,只须要从体积小的物品不断向体积大的物品累加,最后取知足背包体积组合便可,使用mysql中的with表达式便可实现,假设背包的体积为50,sql以下测试
with recursive bag_fill as (select vol, vol as sum_vol,cast(vol as char(500)) as compose from bag0 union select t.vol,t.vol+s.sum_vol, concat(t.vol,'-',s.compose) from bag0 t, bag_fill s where t.vol < s.vol) select sum_vol,compose from bag_fill where sum_vol = 50;
第二个背包问题是01背包,给定一组物品,每种物品都有本身的重量和价格,而且每种物品只有一个,在限定的总重量内,如何选择使得物品的总价格最高
一样的,建立测试数据,此次多了价格列优化
CREATE TABLE `bag1` ( `vol` int(0) NULL DEFAULT NULL, `price` int(0) NULL DEFAULT NULL ); INSERT INTO `bag1` VALUES (17, 50); INSERT INTO `bag1` VALUES (9, 31); INSERT INTO `bag1` VALUES (14, 94); INSERT INTO `bag1` VALUES (4, 11); INSERT INTO `bag1` VALUES (16, 68); INSERT INTO `bag1` VALUES (7, 50); INSERT INTO `bag1` VALUES (18, 14); INSERT INTO `bag1` VALUES (19, 43); INSERT INTO `bag1` VALUES (5, 37); INSERT INTO `bag1` VALUES (12, 51);
解决这个问题的思路跟上一题差很少,一样是从体积小的物品不断向体积大的物品累加体积和价格,取整体积小于等于背包体积,最后按照总价格倒序排列便可
假设背包的体积是50,mysql中写法以下code
with recursive bag_10 as (select vol, vol as sum_vol, price as sum_price, cast(vol as char(500)) as compose from bag1 union select t.vol, s.sum_vol + t.vol, s.sum_price + t.price, concat(t.vol, '-', s.compose) from bag1 t, bag_10 s where t.vol < s.vol and s.sum_vol + t.vol <= 50) select sum_vol,sum_price,compose from bag_10 order by sum_price desc;
下一个问题是彻底背包,与01背包惟一不一样的地方就是每种物品的个数不限,此次用01背包的数据就能够
其实实现的思路差很少,只不过在递归关联的过程当中,由体积小的物品向体积大的物品累加变成了体积小的物品向体积大或者体积相同的物品累加,假设背包的体积为50,mysql的实现方法以下blog
with recursive bag_complete as (select vol, vol as sum_vol, price as sum_price, cast(vol as char(500)) as compose from bag1 union select t.vol, s.sum_vol + t.vol, s.sum_price + t.price, concat(t.vol,'-', s.compose) from bag1 t, bag_complete s where t.vol <= s.vol and s.sum_vol + t.vol <= 50) select sum_vol, sum_price,compose from bag_complete order by sum_price desc;
最后一个问题是多重背包,与彻底背包不一样的地方是每种物品的个数有限,此次再建立一张数据表,增长一列表明每种物品的数量递归
CREATE TABLE `bag2` ( `vol` int(0) NULL DEFAULT NULL, `price` int(0) NULL DEFAULT NULL, `num` int(0) NULL DEFAULT NULL ); INSERT INTO `bag2` VALUES (17, 50, 1); INSERT INTO `bag2` VALUES (9, 31, 1); INSERT INTO `bag2` VALUES (14, 94, 2); INSERT INTO `bag2` VALUES (4, 11, 3); INSERT INTO `bag2` VALUES (16, 68, 2); INSERT INTO `bag2` VALUES (7, 50, 2); INSERT INTO `bag2` VALUES (18, 14, 3); INSERT INTO `bag2` VALUES (19, 43, 2); INSERT INTO `bag2` VALUES (5, 37, 3); INSERT INTO `bag2` VALUES (12, 51, 3);
多重背包相对麻烦一些,直接按照上面的方法递归关联是没法取到全部物品的组合的,个人思路是这样,首先取出每一个物品的本身与本身关联的全部组合,例如体积为4的物品有3个,那么这个物品的全部组合就是4,4-4,4-4-4,而后在用这个组合的结果按照以前的办法由体积小的物品向体积大的物品累加
第一个步骤的sql以下,sum_vol,sum_price分别表明物品与本身组合后的整体积和总价格ip
with recursive bag_compose as (select vol as raw_vol, price, num, vol * num as sum_vol, price * num as sum_price, reverse(substr(reverse(repeat(concat(vol, '-'), num)), 2)) as compose from bag2 union select raw_vol, price, num - 1, raw_vol * (num - 1), price * (num - 1), reverse(substr(reverse(repeat(concat(raw_vol, '-'), num - 1)), 2)) as compose from bag_compose where num > 1) select * from bag_compose order by compose;
with recursive bag_compose as (select vol as raw_vol, price, num, vol * num as sum_vol, price * num as sum_price, reverse(substr(reverse(repeat(concat(vol, '-'), num)), 2)) as compose from bag2 union select raw_vol, price, num - 1, raw_vol * (num - 1), price * (num - 1), reverse(substr(reverse(repeat(concat(raw_vol, '-'), num - 1)), 2)) as compose from bag_compose where num > 1), bag_multiple as (select raw_vol, sum_vol, sum_price, cast(compose as char(500)) as compose from bag_compose as t where sum_vol <= 50 union select t.raw_vol, s.sum_vol + t.sum_vol, s.sum_price + t.sum_price, concat(t.compose, '-', s.compose) from bag_compose t, bag_multiple s where t.raw_vol < s.raw_vol and s.sum_vol + t.sum_vol <= 50) select compose, sum_vol, sum_price from bag_multiple order by sum_price desc;
以上就是背包问题mysql版本的解法,你们有更好的方法,欢迎评论。it