github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/dp/double11_test.go (about)

     1  package dp
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  )
     7  
     8  /*
     9  
    10  双11 满减问题
    11  
    12  购物车中 n 个商品 , 满200减50 ,挑选其中的商品 最小达到满减的条件
    13  
    14  w 满减的券的额度
    15  price 购物车中商品的价格
    16  */
    17  func double11(w int, price []int) {
    18  	n := len(price)
    19  
    20  	// 定义状态 f(商品id,商品价格)
    21  	states := make([][]bool, n)
    22  	wc := 3 * w
    23  	for i := range states {
    24  		states[i] = make([]bool, wc+1) // 满减是要超过,所以价格要大于w
    25  		for j := range states[i] {
    26  			states[i][j] = false
    27  		}
    28  	}
    29  
    30  	// 首个状态
    31  	states[0][0] = true        // 首个商品不买
    32  	states[0][price[0]] = true // 首个商品买
    33  	// 将问题分解成 n个步骤来解决
    34  	for i := 1; i < n; i++ { // 遍历每个商品
    35  		for j := 0; j <= wc; j++ { // 第i个商品不买的情况
    36  			if states[i-1][j] { // 前一个商品已购买的情况
    37  				states[i][j] = states[i-1][j] // 不购买 j不用加上价格
    38  			}
    39  		}
    40  
    41  		for j := 0; j <= wc-price[i]; j++ { // 第i个商品需要购买
    42  			if states[i-1][j] {
    43  				states[i][j+price[i]] = true
    44  			}
    45  		}
    46  	}
    47  
    48  	min := -1
    49  	for j := w; j < wc+1; j++ {
    50  		if states[n-1][j] { // 最小满足条件的最小价格
    51  			min = j // 找到最低价格
    52  			break
    53  		}
    54  	}
    55  	if min == -1 {
    56  		fmt.Println("无解:", min)
    57  		return
    58  	}
    59  	fmt.Println("最低价格是:", min)
    60  	tmp := min
    61  	// 逆推有哪些商品
    62  	sum := 0
    63  	for i := n - 1; i >= 1; i-- {
    64  		if tmp-price[i] >= 0 && states[i-1][tmp-price[i]] { //states[i-1][tmp-price] 说明购买了
    65  			// 最小商品价格减去一个商品的价格,去状态表查看中是否有购买,如果有购买就是的
    66  			fmt.Printf("需要购买第 %v个商品 价格是 %v\n", i, price[i])
    67  			tmp -= price[i]
    68  			sum += price[i]
    69  		} // states[i-1][tmp] 说明没有被购买
    70  	}
    71  	if tmp > 0 && tmp-price[0] == 0 {
    72  		// 第一个商品也购买
    73  		fmt.Printf("需要购买第 %v个商品 价格是 %v\n", 0, price[0])
    74  		sum += price[0]
    75  	}
    76  	fmt.Println("sum:", sum)
    77  }
    78  
    79  func TestDouble11(t *testing.T) {
    80  	sl := []int{3, 5, 7, 1, 2, 8, 9}
    81  	double11(36, sl)
    82  }