1. 程式人生 > >【動態規劃】最少硬幣換取目標錢數【0-1揹包問題】

【動態規劃】最少硬幣換取目標錢數【0-1揹包問題】

/***********************************
最少硬幣換取目標錢數【0-1揹包問題】
***************************************/
/*****************************
思路:
1.建立一張二維表dp,m*n 其中m表示貨幣的種類,行n表示 target+1(即是目標錢數+1)
  dp[ii][jj]:表示 有ii面值貨幣湊夠jj元需要最小的貨幣數。
即是:(下表以目標錢數為5,錢的種類為3表示)
|   0   1    2     3 
-----------------
2 | 1 65535  1      0 
3 | 1 65535 65535 65535  4 | 165535 65535 65535  2.初始化如上表 dp[ii][jj]  表示 用面值為 0,1,。。ii(即是當前面值包括前面的所有面值) 的貨幣對換 jj 元的方法數 3.對硬幣面值按從小到大排序 4.填充表 (1)使用 0 枚面值 ii的貨幣     dp[ii-1][jj-0*value] (2)使用 1 枚面值 jj-count*value<=0為止 (5)比較上述結果,最小值即是dp[ii][jj]的值。 dp[ii][jj] =min{dp[ii][jj - count*value] + count} 時間複雜度:
m*(n+1)  m貨幣種類  n 目標錢數 空間複雜度: m*(n+1)  m貨幣種類  n 目標錢數 ****************************/ int  changeMoneyWithLeastNumber(vector<int>  money, int target) { //定義二維陣列 int **dp = new int*[money.size()]; for (int ii = 0; ii < money.size(); ii++) { dp[ii] = new int[target + 1]; } //填充第一列 for (int
 ii = 0; ii < money.size(); ii++) { dp[ii][0] = 0; } //填充第一行 for (int ii = 1; ii < target + 1; ii++) { if (ii%money[0] == 0) { dp[0][ii] = ii / money[0]; } else { dp[0][ii] = 65535; } } //填充表格 for (int ii = 1; ii < money.size(); ii++) { for (int jj = 1; jj < target + 1; jj++) { int value = money[ii];//這個硬幣的面值 int count = 1;//使用這個面值的硬幣的個數 dp[ii][jj] = dp[ii - 1][jj]; while (jj - count*value >= 0)//分別使用1.2.3.4...張該種面值的貨幣 { if (dp[ii][jj]>dp[ii][jj - count*value] + count) { dp[ii][jj] = dp[ii][jj - count*value] + count; } count++; } } } //輸出表格 for (int ii = 0; ii < money.size(); ii++) { for (int jj = 0; jj < target + 1; jj++) { cout << dp[ii][jj] << "   "; } cout << endl; cout << endl; } cout << endl; //刪除建立的陣列 int  result = dp[money.size() - 1][target]; for (int ii = 0; ii < money.size(); ii++) { delete[]  dp[ii]; } return result; }