0-1揹包問題—回溯演算法—java實現
阿新 • • 發佈:2018-11-28
0-1揹包問題
【問題描述】
有n種可選物品1,…,n ,放入容量為c的揹包內,使裝入的物品具有最大效益。
表示
n :物品個數
c :揹包容量
p1,p2, …, pn:個體物品效益值
w1,w2, …,wn:個體物品容量
【問題解析】
0-1揹包問題的解指:物品1,…,n的一種放法(x1, ···,xn的0/1賦值),使得效益值最大。 假定揹包容量不足以裝入所有物品:面臨選擇 【優化原理】無論優化解是否放物品1,優化解對物品2,…,n的放法,相對剩餘揹包容量,也是優化解。 首先給出所需要的變數: ``` private static int[] p;//物品的價值陣列 private static int[] w;//物品的重量陣列 private static int c;//最大可以拿的重量 private static int count;//物品的個數 private static int cw;//當前的重量 private static int cp;//當前的價值 static int bestp;//目前最優裝載的價值 private static int r;//剩餘物品的價值 private static int[] cx;//存放當前解 private static int[] bestx;//存放最終解 ``` 解空間樹:子集樹 可行性約束條件:cw + w[t] < c 上界函式:cp + r <= bestp,即如果當前結點滿足這個條件時,就可以將該結點的右子樹剪去。
[核心演算法]
``` /** * 回溯 * @param t */ public static void BackTrack(int t) { if(t>count) {//到達葉結點 if(cp>bestp) { for(int i = 1;i<=count;i++) { bestx[i] = cx[i]; } bestp = cp; } return; } r -= p[t]; if(cw + w[t] <= c) {//搜尋左子樹 cx[t] = 1; cp += p[t]; cw += w[t]; BackTrack(t+1); cp -= p[t];//恢復現場 cw -= w[t];//恢復現場 } if(cp + r >bestp) {//剪枝操作 cx[t] = 0;//搜尋右子樹 BackTrack(t+1); } r += p[t];//恢復現場 } ```
[完整程式碼]
``` package sort; public class Zero_One { private static int[] p;//物品的價值陣列 private static int[] w;//物品的重量陣列 private static int c;//最大可以拿的重量 private static int count;//物品的個數 private static int cw;//當前的重量 private static int cp;//當前的價值 static int bestp;//目前最優裝載的價值 private static int r;//剩餘物品的價值 private static int[] cx;//存放當前解 private static int[] bestx;//存放最終解 public static int Loading(int[] ww,int[] pp, int cc) { //初始化資料成員,陣列下標從1開始 count = ww.length - 1; w = ww; p = pp; c = cc; cw = 0; bestp = 0; cx = new int[count+1]; bestx = new int [count+1]; //初始化r,即剩餘最大價格 for(int i = 1;i<=count;i++) { r += p[i]; } //呼叫回溯法計算 BackTrack(1); return bestp; } /** * 回溯 * @param t */ public static void BackTrack(int t) { if(t>count) {//到達葉結點 if(cp>bestp) { for(int i = 1;i<=count;i++) { bestx[i] = cx[i]; } bestp = cp; } return; } r -= p[t]; if(cw + w[t] <= c) {//搜尋左子樹 cx[t] = 1; cp += p[t]; cw += w[t]; BackTrack(t+1); cp -= p[t];//恢復現場 cw -= w[t];//恢復現場 } if(cp + r >bestp) {//剪枝操作 cx[t] = 0;//搜尋右子樹 BackTrack(t+1); } r += p[t];//恢復現場 } public static void main(String[] args) { //測試 int[] w1 = {0,15,25,40,20,15,24}; int[] p1 = {0,10,5,20,2,14,23}; int c1 = 30; Loading(w1,p1,c1); System.out.println("最優裝載為:" + bestp); for(int i =1;i<=count;i++) { System.out.print(bestx[i] + " "); } }