記一次優惠券最優使用算法

記一次優惠券最優使用算法

先說一下業務背景。公司作的一個投資的APP,投資金額能夠用優惠券抵扣。紅包面額(100,50,30,10)php

優惠券使用規則:

  • 優先使用大面額的紅包,即優先使用張數最少的紅包組合
  • 優先使用有限制的紅包,即優先使用有限制紅包張數佔比最大的組合
  • 優先使用即將過時的紅包,即優先使用平均有效期最短的組合
  • 選擇紅包面額之和最大的組合(面額總值≤投資額*1%)

算法嘗試

前面三個均可以經過數據庫檢索排序實現生成一個數組,最後一個就要使用程序算法實現了。
一開始有想過揹包法、窮舉法。算法

  • 揹包法:說實在的,沒看懂(比較尷尬),實現是能夠實現。可是沒法獲取具體使用了哪張優惠券(簡單就是很難得到優惠券的Id)
  • 窮舉法:數據太多,不可控。

優惠券最優算法1.0

算出用戶本次投資最大使用優惠券總額(redAmount)、獲取用戶的優惠券列表(redCoupons)(已按前三規則排序)直接上代碼:數據庫

public function dealCoupon()
    {
        $redCoupons =[]; $restRedAmount = 100;

        $redCouponIdLists = []; $restRedAmounts = [];
        $arrCount = count($redCoupons);
        for ($i=0; $i<$arrCount; $i++) {
            list($redCouponIdList, $restRedAmount) = getBestCoupon($redCoupons, $restRedAmount);
            if ($restRedAmount == 0) {
                $bestCouponIdList = $redCouponIdList;
                break;
            }

            $redCouponIdLists[] = $redCouponIdList;
            $restRedAmounts[] = $restRedAmount;
            array_shift($redCoupons);
        }

        if (empty($bestCouponIdList)) {
            $pos = array_search(min($restRedAmounts), $restRedAmounts);
            $bestCouponIdList = $redCouponIdLists[$pos];
        }

    }

    /**
     * 紅包最優算法
     */
    private function getBestCoupon($redCoupons, $restRedAmount)
    {
        $redCouponAmount = 0;
        foreach ($redCoupons as $redCoupon) {
            if ($restRedAmount >= $redCoupon->getAmount()) {
                $redCouponAmount   = $redCouponAmount + $redCoupon->getAmount());
                $redCouponIdList[] = $redCoupon->getCouponId();
                $restRedAmount     = $restRedAmount - $redCoupon->getAmount();

                if ($restRedAmount == 0) break;
            }
        }

        return [$redCouponIdList, $restRedAmount];
    }

實例解析:用戶投資9000,用戶有優惠券(50,30,30,30,30)

  • 用50塊嘗試,最多80
  • 用第一個30嘗試,最多90,已經最優,中斷程序(不然繼續向下類推)

問題

  • 由於每次算完就把該紅包從數組中推出,這樣仍是存在問題。例如投資1600,用戶有(100,50,30,30)。這樣就不會出現最優。
  • 還有就是沒有按照有效期使用順序。例如投資 7000, 用戶有(50,30,30,30,10)。這樣就會用到後面三張,第一張 30 就沒有用,這個能夠經過推出同面額最後一張解決。

解決(算法2.0)

  • 不把計算過優惠券推出,須要每次把要計算那張優惠券單獨拿出來
  • 這樣程序複雜了不少,但仍是能夠實現的
  • 這樣仍是會出現算法1.0的問題,不過這種按照順序取優惠券很難不出現問題。可是這種面額的優惠券出現概率幾乎沒有

請教

  • 期待有大神給出更好的算法
相關文章
相關標籤/搜索