[紅利贈品最滿意] 某公司週年慶推出贈品酬謝顧客,顧客可使用收集的紅利點數來 兌換贈品,美美希望能夠使用她所累積的紅利點數(假設為 r 點),兌換到最滿意 的贈品組合,請幫她計算:她的全部紅利點數,所能兌換的贈品最大滿意值總和是 多少呢? 下表中列出這家公司所準備的 5 種贈品和兌換所需之紅利點數,以及美美 對於各贈品的滿意值,但因贈品數量有限,兌換完畢即不再補充。 兌換時,假設贈品之滿意總值可以直接將其加總,同一種贈品的兌換數量可超 過一個,但須小於當時該贈品之剩餘數量,最後無法再行兌換的紅利點數可以剩下。 舉例來說,若美美有紅利點數 40 點,贈品 A,B,C,D,E 的剩餘數量分別為 10, 10, 1, 2, 0 個, 則美美可兌換贈品的最大滿意值總和為 160。
輸入/輸出說明:請在表單上建立 2 個 LABEL、7 個 TEXTBOX 及 1 個按鈕,其中第 1 個 LABEL 表示「輸入紅利點數 r」,對應第 1 個 TEXTBOX 可輸入一個正整數;第 2 個 LABEL 表示「分別輸入贈品 A,B,C,D,E 的剩餘數量」,第 2~6 個 TEXTBOX 分別輸 入 5 個正整數 (可包含 0)。按下按鈕,於第 7 個 TEXTBOX 輸出兌換的贈品最大滿意 值總和。 程式執行順序:輸入紅利點數 r,輸入贈品 A,B,C,D,E 的剩餘數量,按下按鈕,輸出。 此題類似背包問題,可以先看看之前我的一些論述。 背包問題 演算法: 家豪版 Youtube 暴力法教學影片 cpp 程式 #include <iostream> #include <math.h> using namespace std; int main() { int x; int Max,a,b,c,d,e,s,N; int a1,b1,c1,d1,e1;//目前可使用的產品數 int a2,b2,c2,d2,e2; N=40;//40點 Max = 0;//目前最大滿意值 a1=min(10,N/30);//A產品需要 30 點,N/30=1,只能換 1 個 b1=min(10,N/18);//B產品需要 18 點,N/18=2,只能換 2 個 c1=min(1,N/10);//C產品需要 10 點,N/10=4,但產品數為 1,所以只能換 1 個 d1=min(2,N/5);//D產品需要 5 點,N/5=8,但產品數為 2,所以只能換 2 個 e1=min(0,N/1);//E產品需要 1 點,N/1=40,但產品數為 0,所以只能換 0 個 for(a=0;a<=a1;a++) for(b=0;b<=b1;b++) for(c=0;c<=c1;c++) for(d=0;d<=d1;d++) for(e=0;e<=e1;e++){ s = a*30 + b*18 + c*10 + d*5 + e*1;//消耗的點數 if(s<=N){//消耗點數小於等於 N 才可以 x = a*100 + b*75 + c*45 + d*20 + e*3;//滿意值 if(x>Max){ Max = x; a2=a;b2=b;c2=c;d2=d;e2=e;//紀錄最大值發生時的產品數 } } } cout << "A=" << a2 << ",B=" << b2 << ",C=" << c2 << ",D=" << d2 << ",E=" << e2 << ", 最大值=" << Max << endl; return 0; } 動態規劃法 Youtube 教學影片 主程式(紅色區), 換物遞迴副程式 P_to_S(目前換到的總喜悅值, 開始兌換起始編號, 可用點數) (藍色區) 遞迴版 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer init() uP = 0 : Cmax = 0 freePoin = TextBox7.Text "可用點數 TextBox6.Text = P_to_S(0, 0, freePoin) "得到最大值 For i = 0 To bestP "show 出買的物品 TextBox6.Text = nameP(best(i, 0)) & "*" & best(i, 1) & If(i = 0, " = ", " , ") & TextBox6.Text Next End Sub "遞迴找滿意度, 傳入 : 目前分配總值 total, 從第幾項物品開始計算 n, 剩餘可用點數 fp, 傳回 : 最好的滿意度 Dim a As Integer, b As Integer, i As Integer, c As Integer, max As Integer
End FunctionIf ((star >= NN) Or (fp <= 0)) Then Return (0) For i = star To NN - 1 a = Math.Min(fp \ Points(i), Surplus(i)) Do While a > 0 b = fp - Points(i) * a "剩餘點數 c = Satisfaction(i) * a "得到的喜悅度 unit(uP, 0) = i : unit(uP, 1) = a : uP += 1 "紀錄換的物品 If (b > 0) Then "還有餘點, 可以再分配其他 c += P_to_S(total + c, i + 1, b) End If If (c > max) Then max = c If (total + c > Cmax) Then copyArray() Cmax = total + c End If a -= 1 uP -= 1 Loop Next Return (max) "將目前最好的情況記錄在 best 陣列 Sub copyArray() Dim i As Integer For i = 0 To uP - 1 best(i, 0) = unit(i, 0) : best(i, 1) = unit(i, 1) "(註標 0 是物品編號 , 註標 1 是物品數量 Next bestP = uP - 1 End Sub Sub init() 昊朋版 黃翰版 此版是用暴力法,但程式也不簡潔,既然都暴力法了,就不用存那麼多變數。 簡單明潦列舉,並記住最大就好。 Dim arr(100) As Integer, current As Integer = 0 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim r As Integer = Val(TextBox1.Text) |