2023年8月1日发(作者:)
运⽤分⽀定界法(分⽀限界法)解决01背包问题⾸先初始化总容量capacity = 10、物品总数量number = 4物品信息为【4,40】、【7、42】、【5、25】、【3、12】,分别为重量weight,价值value。解决该题⽬运⽤到的数据结构有:优先队列、⼆叉树、存放物品基本信息的数组这⾥主要就是构建⼆叉树,⼆叉树节点的属性有weight(当前总容量)value(当前总价值)layer(当前层级,⽤来判断是否为叶⼦节点)currentSolution(当前解,算出最⼤价值后,⽅便找出拿了哪些物品)up(上限)left(左孩⼦,取当前物品)right(右孩⼦,不取当前物品)树如下说下各个节点的值是怎么算的这是根节点,所以初始化weight为0、value为0、up为剩余的物品最有可能能取到的最⼤价值。所以up = 当前剩余容量 * (value /weight) = 10 * (40 / 4) = 100。layer层级为0。取第⼀个物品时。weight = 第⼀个物品的weight = 4,value同理。layer层级为1,currentSolution为1(1代表取)up = 当前总价值 + 当前剩余容量 * (第⼆个物品的value / 第⼆个物品的weight)= 40 + (10 - 4) * (42 / 7) = 76不取第⼀个物品。weight = 0,value = 0。layer层级为1,currentSolution为0(0代表取)up = 当前剩余容量 * (第⼆个物品的value / 第⼆个物品的weight)= 10 * (42 / 7) = 60取第⼀个物品、取第⼆个物品。weight = 4 + 第⼆个物品weight = 4 + 7 = 11 > 最⼤容量10。所以该节点不⽤继续计算和保存。取第⼀个物品、不取第⼆个物品。weight = 原来的weight = 4,value = 原来的value = 40,layer层级为2,currentSolution为10up = 当前总价值value + 剩余容量 * (第三个物品的value / 第三个物品的weight)= 40 + (10 - 4) * (25 / 5) = 70取第⼀个物品、不取第⼆个物品、取第三个物品。weight = 已有weight + 第三个物品weight = 4 + 5 = 9,value = 已有value + 第三个物品value = 40 + 25 = 65。layer层级为3,currentSolution为101。up = 当前总价值value + 剩余容量 * (第四个物品的value / 第四个物品的weight)= 65 + (10 - 9) * (12 / 3) = 69取第⼀个物品、不取第⼆个物品、取第三个物品、不取第四个物品。weight = 已有weight = 9,value同理。layer层级为4,currentSolution为1010。因为layer = 物品总数量number = 4所以up = 当前总价值value其它的节点计算⽅式同理。所以根据以上⽅式,最后可以计算出⼀棵⼆叉树。再对其节点进⾏判断。对于左右分⽀,我们并不知道最终答案是在哪个分⽀下⾯,所以两个分⽀都要判断,不过不能太盲⽬。应该有⼀个查找侧重点,因为答案在up值更⼤的节点下⾯可能性更⼤,所以我们有限查找up值较⼤的节点。这⾥就需要⼀个优先队列,把左右节点放⼊到队列中,up值⼤的放在前⾯,优先出队。最后代码(注释就是思路)。⼀共有5个类,Backpack、BinaryTree、ItemInfo、Node、ckage ck;/** *
物品基本信息 */public class ItemInfo { /** *
重量 */ private int weight; /** *
价值 */ private int value; public ItemInfo() {} public ItemInfo(int weight, int value) { = weight; = value; } public int getWeight() { return weight; } public void setWeight(int weight) { = weight; } public int getValue() { return value; } public void setValue(int value) { = value; }}ckage ck;/** *
分⽀定界法,节点属性 *
分⽀定界法,节点属性 */public class Node extends ItemInfo implements Comparable { /** *
层级,⽤来判断是否为叶⼦节点 */ private int layer; /** *
当前解,算出最⼤价值后,⽅便找出拿了哪些物品 */ private String currentSolution; /** *
上限 */ private double up; /** *
取 */ private Node left; /** *
不取 */ private Node right; public Node() {} public int getLayer() { return layer; } public void setLayer(int layer) { = layer; } public String getCurrentSolution() { return currentSolution; } public void setCurrentSolution(String currentSolution) { tSolution = currentSolution; } public double getUp() { return up; } public void setUp(double up) { = up; } public Node getLeft() { return left; } public void setLeft(Node left) { = left; } public Node getRight() { return right; } public void setRight(Node right) { = right; } /** *
优先队列排列⽅式,根据up值⼤⼩来排序 * @param o Node * @return int */ @Override public int compareTo(Object o) { Node node = (Node) o; if(() > ()) { return 1; } else if(() == ()) { return 0; } return -1; }}ckage ck;import .*;/*4 104 407 425 253 12*//** *
背包 */public class Backpack { /** *
总容量 */ private int capacity; /** *
总数量 */ private int number; public BinaryTree binaryTree; /** *
初始化 */ public void initialization() { //
创建根节点 Node head = new Node(); ght(0); ue(0); er(0); rentSolution(""); //
根据每单位质量价值来从⼤到⼩排序 mInfoList().sort((o1, o2) -> { Double a = (double) (ue() / ght()); Double a = (double) (ue() / ght()); Double b = (double) (ue() / ght()); return eTo(a); }); ItemInfo firstNode = mInfoList().get(0); (capacity * (ue() * 1.0 / ght())); kpack(this); //
创建树 dBinaryTree(head, 0); Bound(head); } public void input() { Scanner scanner = new Scanner(); //
物品数量 number = t(); //
背包容量 capacity = t(); mInfoList(new ArrayList<>(number)); for(int i = 0; i < number; i++) { int weight = t(); int value = t(); ItemInfo itemInfo = new ItemInfo(weight, value); mInfoList().add(itemInfo); } } public int getCapacity() { return capacity; } public int getNumber() { return number; } public void setNumber(int number) { = number; } public void setCapacity(int capacity) { ty = capacity; }}ckage ck;import ;import tyQueue;import ;/** *
处理节点树 */public class BinaryTree { /** *
保存所有物品的基本信息,根据每单位质量价值从⼤到⼩来排序 */ private List
最优解(假如为:1010,代表第⼀个拿,第⼆个不拿,第三个拿,第四个不拿) */ */ private String bestSolution; /** *
最优值 */ private int max; private Backpack backpack; /** *
判断节点是否符合要求 * @param node
树的当前节点 * @param upPriorityQueue
优先队列 */ private void judgementNode(Node node, Queue
当前节点对应的总重量超过背包最⼤容量 ||
当前节点最可能的最⼤价值up⼩于已知的价值 // ght() > acity()这个判断其实是多余的。。 if(ght() > acity() || () < max) { return; } //
当前的节点对应的层级是否⼩于总数量 if(er() < ber()) { (node); } else { //
更新最优价值 max = ue(); //
更新最优解 bestSolution = rentSolution(); } } /** *
分⽀界定 * @param node
根节点 */ public void branchBound(Node node) { //
使⽤优先队列,根据节点的up值,优先权由⼤到⼩ Queue
如果队列中第⼀个节点的up值⼩于最优价值,则就没必要继续遍历队列。 if(() <= max) { break; } judgementNode(t(), upPriorityQueue); judgementNode(ht(), upPriorityQueue); } } /** *
创建⼆叉树 * @param node
当前节点 * @param index
物品List对应下标 */ public void createdBinaryTree(Node node, int index) { if(index >= ber()) { return; } //
获取当前物品信息 ItemInfo currentItem = (index); if(t() == null) { Node leftNode = new Node(); //
因为是左节点,代表拿。被拿当前物品价值+已有的物品总价值 //
因为是左节点,代表拿。被拿当前物品价值+已有的物品总价值 ue(ue() + ue()); //
被拿当前物品重量+已有的物品总重量 ght(ght() + ght()); //
设置层级index从0开始,0代表根节点的层级 er(index + 1); //
算出剩余容量 int surplus = acity() - ght(); //
这⾥进⾏减去枝,如果剩余容量⼩于0说明当前物品⽆法放⼊ if(surplus >= 0) { //
如果不是最后⼀层,index在这⾥,可以理解为层级 if(index + 1 < ()) { //
当前物品的下⼀个物品 ItemInfo nextNode = (index + 1); //
求出剩余物品的最⼤up值,下⼀个物品每单位容量最⼤价值*剩余容量 int up = surplus * (ue() / ght()); //
是否为根节点 if(index == 0) { //
根节点只需要获取当前物品的价值+up (up + ue()); } else { //
⾮根节点需要获取当前总价值+up (up + ue()); } } else { //
最后⼀层,其实就是最后⼀个物品,对应最后⼀层的节点的up就是当前节点的value (ue()); } //
更新解过程,1代表left,即拿取 rentSolution(rentSolution() + 1); t(leftNode); createdBinaryTree(t(), index + 1); } } if(ht() == null) { Node rightNode = new Node(); //
因为是右节点,代表不拿。所以直接设置为已有的物品总价值 ue(ue()); ght(ght()); er(index + 1); int surplus = acity() - ght(); if(surplus >= 0) { if(index + 1 < ()) { ItemInfo nextNode = (index + 1); int up = surplus * (ue() / ght()); if(index == 0) { (up); } else { (up + ue()); } } else { (ue()); } rentSolution(rentSolution() + 0); ht(rightNode); createdBinaryTree(ht(), index + 1); } } } /** *
遍历树 * @param node
节点 */ public void preOrderBinaryTree(Node node) { if(node != null) { if(node != null) { n(ng()); preOrderBinaryTree(t()); preOrderBinaryTree(ht()); } } public List
运⽤分⽀定界法解决背包问题 */public class Main { public static void main(String[] args) { Backpack backpack = new Backpack(); Tree = new BinaryTree(); (); lization(); n("最⼤价值为:" + ()); String bestSolution = tSolution(); n("拿取的物品为:"); for(int i = 0; i < (); i++) { if((i) != '0') { ItemInfo itemInfo = mInfoList().get(i); n("[" + ght() + " " + ue() + "]"); } } }}测试4 104 407 425 253 12最⼤价值为:65拿取的物品为:[4 40][5 25]
2023年8月1日发(作者:)
运⽤分⽀定界法(分⽀限界法)解决01背包问题⾸先初始化总容量capacity = 10、物品总数量number = 4物品信息为【4,40】、【7、42】、【5、25】、【3、12】,分别为重量weight,价值value。解决该题⽬运⽤到的数据结构有:优先队列、⼆叉树、存放物品基本信息的数组这⾥主要就是构建⼆叉树,⼆叉树节点的属性有weight(当前总容量)value(当前总价值)layer(当前层级,⽤来判断是否为叶⼦节点)currentSolution(当前解,算出最⼤价值后,⽅便找出拿了哪些物品)up(上限)left(左孩⼦,取当前物品)right(右孩⼦,不取当前物品)树如下说下各个节点的值是怎么算的这是根节点,所以初始化weight为0、value为0、up为剩余的物品最有可能能取到的最⼤价值。所以up = 当前剩余容量 * (value /weight) = 10 * (40 / 4) = 100。layer层级为0。取第⼀个物品时。weight = 第⼀个物品的weight = 4,value同理。layer层级为1,currentSolution为1(1代表取)up = 当前总价值 + 当前剩余容量 * (第⼆个物品的value / 第⼆个物品的weight)= 40 + (10 - 4) * (42 / 7) = 76不取第⼀个物品。weight = 0,value = 0。layer层级为1,currentSolution为0(0代表取)up = 当前剩余容量 * (第⼆个物品的value / 第⼆个物品的weight)= 10 * (42 / 7) = 60取第⼀个物品、取第⼆个物品。weight = 4 + 第⼆个物品weight = 4 + 7 = 11 > 最⼤容量10。所以该节点不⽤继续计算和保存。取第⼀个物品、不取第⼆个物品。weight = 原来的weight = 4,value = 原来的value = 40,layer层级为2,currentSolution为10up = 当前总价值value + 剩余容量 * (第三个物品的value / 第三个物品的weight)= 40 + (10 - 4) * (25 / 5) = 70取第⼀个物品、不取第⼆个物品、取第三个物品。weight = 已有weight + 第三个物品weight = 4 + 5 = 9,value = 已有value + 第三个物品value = 40 + 25 = 65。layer层级为3,currentSolution为101。up = 当前总价值value + 剩余容量 * (第四个物品的value / 第四个物品的weight)= 65 + (10 - 9) * (12 / 3) = 69取第⼀个物品、不取第⼆个物品、取第三个物品、不取第四个物品。weight = 已有weight = 9,value同理。layer层级为4,currentSolution为1010。因为layer = 物品总数量number = 4所以up = 当前总价值value其它的节点计算⽅式同理。所以根据以上⽅式,最后可以计算出⼀棵⼆叉树。再对其节点进⾏判断。对于左右分⽀,我们并不知道最终答案是在哪个分⽀下⾯,所以两个分⽀都要判断,不过不能太盲⽬。应该有⼀个查找侧重点,因为答案在up值更⼤的节点下⾯可能性更⼤,所以我们有限查找up值较⼤的节点。这⾥就需要⼀个优先队列,把左右节点放⼊到队列中,up值⼤的放在前⾯,优先出队。最后代码(注释就是思路)。⼀共有5个类,Backpack、BinaryTree、ItemInfo、Node、ckage ck;/** *
物品基本信息 */public class ItemInfo { /** *
重量 */ private int weight; /** *
价值 */ private int value; public ItemInfo() {} public ItemInfo(int weight, int value) { = weight; = value; } public int getWeight() { return weight; } public void setWeight(int weight) { = weight; } public int getValue() { return value; } public void setValue(int value) { = value; }}ckage ck;/** *
分⽀定界法,节点属性 *
分⽀定界法,节点属性 */public class Node extends ItemInfo implements Comparable { /** *
层级,⽤来判断是否为叶⼦节点 */ private int layer; /** *
当前解,算出最⼤价值后,⽅便找出拿了哪些物品 */ private String currentSolution; /** *
上限 */ private double up; /** *
取 */ private Node left; /** *
不取 */ private Node right; public Node() {} public int getLayer() { return layer; } public void setLayer(int layer) { = layer; } public String getCurrentSolution() { return currentSolution; } public void setCurrentSolution(String currentSolution) { tSolution = currentSolution; } public double getUp() { return up; } public void setUp(double up) { = up; } public Node getLeft() { return left; } public void setLeft(Node left) { = left; } public Node getRight() { return right; } public void setRight(Node right) { = right; } /** *
优先队列排列⽅式,根据up值⼤⼩来排序 * @param o Node * @return int */ @Override public int compareTo(Object o) { Node node = (Node) o; if(() > ()) { return 1; } else if(() == ()) { return 0; } return -1; }}ckage ck;import .*;/*4 104 407 425 253 12*//** *
背包 */public class Backpack { /** *
总容量 */ private int capacity; /** *
总数量 */ private int number; public BinaryTree binaryTree; /** *
初始化 */ public void initialization() { //
创建根节点 Node head = new Node(); ght(0); ue(0); er(0); rentSolution(""); //
根据每单位质量价值来从⼤到⼩排序 mInfoList().sort((o1, o2) -> { Double a = (double) (ue() / ght()); Double a = (double) (ue() / ght()); Double b = (double) (ue() / ght()); return eTo(a); }); ItemInfo firstNode = mInfoList().get(0); (capacity * (ue() * 1.0 / ght())); kpack(this); //
创建树 dBinaryTree(head, 0); Bound(head); } public void input() { Scanner scanner = new Scanner(); //
物品数量 number = t(); //
背包容量 capacity = t(); mInfoList(new ArrayList<>(number)); for(int i = 0; i < number; i++) { int weight = t(); int value = t(); ItemInfo itemInfo = new ItemInfo(weight, value); mInfoList().add(itemInfo); } } public int getCapacity() { return capacity; } public int getNumber() { return number; } public void setNumber(int number) { = number; } public void setCapacity(int capacity) { ty = capacity; }}ckage ck;import ;import tyQueue;import ;/** *
处理节点树 */public class BinaryTree { /** *
保存所有物品的基本信息,根据每单位质量价值从⼤到⼩来排序 */ private List
最优解(假如为:1010,代表第⼀个拿,第⼆个不拿,第三个拿,第四个不拿) */ */ private String bestSolution; /** *
最优值 */ private int max; private Backpack backpack; /** *
判断节点是否符合要求 * @param node
树的当前节点 * @param upPriorityQueue
优先队列 */ private void judgementNode(Node node, Queue
当前节点对应的总重量超过背包最⼤容量 ||
当前节点最可能的最⼤价值up⼩于已知的价值 // ght() > acity()这个判断其实是多余的。。 if(ght() > acity() || () < max) { return; } //
当前的节点对应的层级是否⼩于总数量 if(er() < ber()) { (node); } else { //
更新最优价值 max = ue(); //
更新最优解 bestSolution = rentSolution(); } } /** *
分⽀界定 * @param node
根节点 */ public void branchBound(Node node) { //
使⽤优先队列,根据节点的up值,优先权由⼤到⼩ Queue
如果队列中第⼀个节点的up值⼩于最优价值,则就没必要继续遍历队列。 if(() <= max) { break; } judgementNode(t(), upPriorityQueue); judgementNode(ht(), upPriorityQueue); } } /** *
创建⼆叉树 * @param node
当前节点 * @param index
物品List对应下标 */ public void createdBinaryTree(Node node, int index) { if(index >= ber()) { return; } //
获取当前物品信息 ItemInfo currentItem = (index); if(t() == null) { Node leftNode = new Node(); //
因为是左节点,代表拿。被拿当前物品价值+已有的物品总价值 //
因为是左节点,代表拿。被拿当前物品价值+已有的物品总价值 ue(ue() + ue()); //
被拿当前物品重量+已有的物品总重量 ght(ght() + ght()); //
设置层级index从0开始,0代表根节点的层级 er(index + 1); //
算出剩余容量 int surplus = acity() - ght(); //
这⾥进⾏减去枝,如果剩余容量⼩于0说明当前物品⽆法放⼊ if(surplus >= 0) { //
如果不是最后⼀层,index在这⾥,可以理解为层级 if(index + 1 < ()) { //
当前物品的下⼀个物品 ItemInfo nextNode = (index + 1); //
求出剩余物品的最⼤up值,下⼀个物品每单位容量最⼤价值*剩余容量 int up = surplus * (ue() / ght()); //
是否为根节点 if(index == 0) { //
根节点只需要获取当前物品的价值+up (up + ue()); } else { //
⾮根节点需要获取当前总价值+up (up + ue()); } } else { //
最后⼀层,其实就是最后⼀个物品,对应最后⼀层的节点的up就是当前节点的value (ue()); } //
更新解过程,1代表left,即拿取 rentSolution(rentSolution() + 1); t(leftNode); createdBinaryTree(t(), index + 1); } } if(ht() == null) { Node rightNode = new Node(); //
因为是右节点,代表不拿。所以直接设置为已有的物品总价值 ue(ue()); ght(ght()); er(index + 1); int surplus = acity() - ght(); if(surplus >= 0) { if(index + 1 < ()) { ItemInfo nextNode = (index + 1); int up = surplus * (ue() / ght()); if(index == 0) { (up); } else { (up + ue()); } } else { (ue()); } rentSolution(rentSolution() + 0); ht(rightNode); createdBinaryTree(ht(), index + 1); } } } /** *
遍历树 * @param node
节点 */ public void preOrderBinaryTree(Node node) { if(node != null) { if(node != null) { n(ng()); preOrderBinaryTree(t()); preOrderBinaryTree(ht()); } } public List
运⽤分⽀定界法解决背包问题 */public class Main { public static void main(String[] args) { Backpack backpack = new Backpack(); Tree = new BinaryTree(); (); lization(); n("最⼤价值为:" + ()); String bestSolution = tSolution(); n("拿取的物品为:"); for(int i = 0; i < (); i++) { if((i) != '0') { ItemInfo itemInfo = mInfoList().get(i); n("[" + ght() + " " + ue() + "]"); } } }}测试4 104 407 425 253 12最⼤价值为:65拿取的物品为:[4 40][5 25]
发布评论