动态规划——双11既可以薅羊毛还能花钱最少
淘寶的“雙十一”購物節(jié)有各種促銷活動,比如“滿 200 元減 50 元”。假設(shè)你的購物車中有 n 個(n>100)想買的商品,希望從里面選幾個,在湊夠滿減條件的前提下,讓選出來的商品價格總和最大程度地接近滿減條件(200 元),這樣就可以極大限度地“薅羊毛”。
回溯法
我們假設(shè)購物滿w元才能減。例如滿500減200,那w=500。購物車中商品的價格int[] price表示。每次決定第i個物品要不要購買,當(dāng)物品選完了或者總價夠w,停止選擇。比較選中物品價格總和最低的一組選擇。這是一個多階段決策最優(yōu)化問題。可以先用回溯算法解決。
public class Shopping {private int[] price = new int[]{198,201,345,200};private int w = 500;private int minPrice = Integer.MAX_VALUE;private List<Integer> selectItems;private void f (int i,int priceSum,boolean[] shoppingStatus){if(priceSum>w){if(priceSum<minPrice){minPrice = priceSum;selectItems = new ArrayList<Integer>();for(int j=0;j<shoppingStatus.length;j++){if(shoppingStatus[j]){selectItems.add(j);}}}return;}if(i==price.length) return;shoppingStatus[i] = true;f(i+1,priceSum+price[i],shoppingStatus);//選擇第i件商品shoppingStatus[i] = false;f(i+1,priceSum,shoppingStatus);//不選擇第i件商品}public void decision(){boolean[] shoppingStatus = new boolean[price.length];f(0,0,shoppingStatus);} }遞歸樹
遞歸樹中的每個節(jié)點(diǎn)是一個狀態(tài),用(i,preSum)表示。i表示將要處理第i個商品。preSum表示當(dāng)前狀態(tài)下已經(jīng)購買商品的價格和。可以看到這里的狀態(tài)表示的參數(shù)基本和f函數(shù)的參數(shù)是相同的。
在這個例子中,(i,preSum)相同的節(jié)點(diǎn)正好都只有一個,但不排除有多個節(jié)點(diǎn)的可能性。
狀態(tài)表
根據(jù)(i,preSum)我們知道用一個二維表可以表示各種不同的狀態(tài)。第一維(行)是商品下標(biāo),第二維(列)是商品總價。又因為題目要求價格和需要大于w,但我們又不能讓商品和太大,太大優(yōu)惠就沒有必要了。我們需要給商品總價一個最大值3w。
狀態(tài)表boolean[][] states。
第0個商品決策之后,states[0][0]=true;states[0][198]=true。
第1個商品決策之后,states[1][0]=true;states[1][201]=true;states[1][198]=true;states[1][399]=true;
…
我們在states[n-1]從下標(biāo)w開始找值為true的元素下標(biāo)。最先找到的就是符合要求的最小價格。
它與萊文斯坦距離、矩陣中的最短路徑長度不同的地方是,不需要在每一步?jīng)Q策之后只保留最小值,其他節(jié)點(diǎn)放棄。
我想這里沒有放棄其他節(jié)點(diǎn),是因為這里的每一個狀態(tài)可能就是最終答案。第i個商品是不是購買,和第i-1個商品決策之后的所有狀態(tài)有關(guān)系。
當(dāng)然,這道題目還要一個難點(diǎn)是要輸出選擇了哪些商品。當(dāng)我們知道滿足要求的最低總價是minPrice。也就是說states[n-1][minPrice]=true。如果states[n-2][minPrice]=true,則說明第n-1號物品是被放棄的,不購買的。如果states[n-2][minPrice-price[n-1]]=true,說明是購買第n-1號商品的。繼續(xù)遞歸往回查找。
總結(jié)
以上是生活随笔為你收集整理的动态规划——双11既可以薅羊毛还能花钱最少的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle存储过程 使用游标、数组的配
- 下一篇: node安装以后npm下载失败全套处理方