这是一道简化的背包问题:有一背包能容纳 50kg 的物品,现有 9 种物品(它们的重量分别是5kg、8

kg、20kg、35kg、41kg、2kg、15kg、10kg、9kg),要刚好能装满背包,有多少种物品组合?

由于要用到 SQL 来处理,我们先把上面的物品的重量的数据存到表中,并给每种物品分配一个编号。物品表 bag 的数据如下:

id         num  
------  --------
001            5
002            8
003           20
004           35
005           41
006            2
007           15
008           10
009            9

我们的解题思路也是非常简单、粗暴,就是把所有物品的可能的组合的重量都算出来,最后只取总量是 50kg 的组合。当然,在这个过程中可以做些优化的工作。

那怎么求组合呢?用自关联。比如,求任意两种物品的组合,SQL 可以这么写:

SELECT 
  bag a,
  bag b 
WHERE a.id < b.id 

条件 a.id < b.id 用于去掉重复的组合。比如,物品 001 和物品 002,不管是 001 & 002 或者 002 & 001 ,都属于一个组合。

我们可以像上一篇文章一样,使用递归枚举出所有的组合。

WITH RECURSIVE t (id, total, path, formula, next_id) AS 
(SELECT 
  num AS total,
  CAST(id AS CHAR(100)) AS path,
  CAST(num AS CHAR(100)) AS formula,
  id AS next_id 
UNION ALL 
SELECT 
  t.id,
  t.total + a.num AS total,
  CAST(
    CONCAT(t.path, ' & ', a.id) AS CHAR(100)
  ) AS path,
  CONCAT(
    formula,
    ' + ',
    CAST(num AS CHAR(100))
  ) AS formula,
  a.id AS next_id 
  bag a 
WHERE t.next_id < a.id 
  AND t.total + a.num <= 50) 
SELECT 
  formula,
  total,
WHERE total = 50 

其中,字段 path 和 formula 只是为了让结果看起来更友好,去掉它们对整个计算过程没有影响。

关键的处理逻辑是这段代码:

WITH RECURSIVE t (id, total, next_id) AS 
(SELECT 
  num AS total,
  id AS next_id 
UNION ALL 
SELECT 
  t.id,
  t.total + a.num AS total,
  a.id AS next_id 
  bag a 
WHERE t.next_id < a.id 
  AND t.total + a.num <= 50) 

total 是组合中的数值加和的结果,条件 t.next_id < a.id 是为了保证组合中的物品的编号按一定的顺序(从小到大)排序,防止出现重复的组合;条件 t.total + a.num <= 50 提前过滤掉不满足的组合,减少计算的次数。

最终的输出结果 >>>

formula               total  path                         
-------------------  ------  -----------------------------
35 + 15                  50  004 & 007                    
41 + 9                   50  005 & 009                    
5 + 35 + 10              50  001 & 004 & 008              
5 + 8 + 35 + 2           50  001 & 002 & 004 & 006        
5 + 20 + 15 + 10         50  001 & 003 & 007 & 008        
5 + 8 + 20 + 2 + 15      50  001 & 002 & 003 & 006 & 007  
                    这是一道简化的背包问题:有一背包能容纳 50kg 的物品,现有 9 种物品(它们的重量分别是5kg、8kg、20kg、35kg、41kg、2kg、15kg、10kg、9kg),要刚好能装满背包,有多少种物品组合?由于要用到 SQL 来处理,我们先把上面的物品的重量的数据存到表中,并给每种物品分配一个编号。物品表 bag 的数据如下:id         num  ------  --------001            5002            8003           200
				
今天遇到一个表单,要求按名字分物品种类,如图是表内容 要求查询一个名字下的所有物品sql语句:select UserID,UserName,group_concat(Goods order by Goods separator ' , ') as Goods,GdTime from pergoods group by UserName 执行结果: 其中使用一个group_co...
sys.dbms_job.submit(job =&gt; job_id, what =&gt; ‘clear_fr_info;’, next_date =&gt; sysdate, 一、背包问题 1. 题目 有 N 件物品和一个容量为 V 的背包。第 i 件物品的费用是 w[i]w [i]w[i] ,价值是v[i]v[i]v[i],求将哪些物品装入背包可使价值总和最大。 比如:有四件物品,编号,体积和价值如下图所示 2. 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即f[i][j]f[i] 大概意思就是随机选择几个人使得总分最接近某个值,这不正是数学中学习过的排列组合中的组合吗? 排列组合中A(15,3)表示排列,从15个中有序抽取3个,所以一共有15*14*13种排列结果,123、132、213、231、312、321表示6种不同的结果 排列组合中C(15,3)表示组合,从15个中无序选择3个,所以一共有(15*14*13)/(3*2*1)种组合结果,123、132、213、231、312、321表示同一种结果 大概思路:如果使用 很多时候,在关系数据库中,要在查询中显示的信息位于多个表中。这引出了一个问题“你如何结合多个表的结果?” 本课程的所有示例均基于Microsoft SQL Server Management Studio和AdventureWorks2012数据库。 我可以将多个查询的结... 关于部分背包问题(注意不是01背包问题),已知有5种物品和一个可容纳15kg重量的背包,每种物品重量/价值分别为12kg/4,2kg/2,2kg/2,2kg/2,1kg/2,1kg/1,1kg/1,1kg/1和4kg/10$。假定将物品i的某一部分xi放入背包就会得到vixi的效益(0 < xi < 1, vi > 0) ,采用怎样的装包方法才会使装入背包物品的总效益为最大呢?设计贪心策略,输出在该策略下装入背包的最大价值。` 解题思路: 首先,我们要明白部分背包问题和0/1 WITH items AS ( SELECT 1 as item, 10 as weight, 60 as value UNION ALL SELECT 2 as item, 20 as weight, 100 as value UNION ALL SELECT 3 as item, 30 as weight, 120 as value UNION ALL SELECT 4 as item, 40 as weight, 160 as value matrix AS ( SELECT TOP ((SELECT SUM(weight) FROM items) + 1) ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS w, f1 = 0, f2 = 0, f3 = 0, f4 = 0 FROM sys.all_objects a CROSS JOIN sys.all_objects b result AS ( SELECT w, f1, f2, f3, f4, mx = CASE WHEN w < weight THEN f1 ELSE MAX(f1, value + (SELECT MAX(matrix.f1) FROM matrix WHERE w - weight = matrix.w)) FROM matrix CROSS APPLY items SELECT MAX(mx) AS maxValue FROM result; 这个查询使用了CTE(公用表表达式)和动态规划算法来实现背包问题,其中items子查询用来定义背包中的物品,matrix子查询用来创建一个矩阵,result子查询用来通过动态规划算法计算每个容量的最大价值,最终通过MAX函数返回最大价值。