簡體   English   中英

如何使用動態規划解決硬幣排問題?

[英]How do I solve the Coin Row problem using dynamic programming?

硬幣排問題:有一排 n 個硬幣,其值為正整數 C0、C2、...。 . . , Cn-1, 不一定不同。 目標是在初始行中沒有兩個相鄰的硬幣不能被拾取的約束下,拾取最大數量的錢。

在下面的代碼中,n 是我的數組 C 的大小(或硬幣數量),此代碼返回值 [10, 2, 4, 6, 3, 9, 5] 的正確結果(正確的結果是25)。 但是當我為值 [3, 12, 10] 或 [3, 12, 10, 2] 運行相同的代碼時,我得到了錯誤的結果。 (對於一組值,結果應分別為 13 和 14)。

請幫我修復我的代碼。

int max(int a, int b) {
  if(a > b) return a;
  return b;
}

int coin_row(int[] C, int n) {
  if(n==1) return C[0];
  if(n==2) return max(C[0],C[1];

  int F[n], i;
  F[0] = 0; F[1] = C[0];

  for(i = 2;i < n;i++) {
    F[i] = max(C[i] + F[i-2], F[i-1]);
  }

  return F[n-1];
}

所有數字都是正數的聲明使事情變得容易一些。 從這些信息中,我們可以確定我們永遠不想跳過兩個連續的數字。 我們只需要使用第一個數字計算可能的最佳序列,並將其與使用第二個數字可能的最佳序列進行比較。 這是遞歸的理想選擇。

int coin_row(int *C, int n) 
{
    int first_total;
    int second_total;

    if (n == 0) return 0;
    if (n == 1) return *C;
    if (n == 2) return max(*C, *(C+1));

    first_total = *C + coin_row(C+2, n-2);
    second_total = *(C+1) + coin_row(C+3, n-3);
    return(max(first_total, second_total));
}

通過將問題分解為一系列對,我們將列表視為大型二叉樹。 在每一對中,您都可以選擇第一個或第二個數字。 計算每個子樹的總數並返回最大值。 例如,使用 {10, 2, 4, 6, 3, 9, 5} 您的路徑是:

          10                    2
          /\                   /\
         4  6                 6  3
        /\  /\               /\  /\
       3  9 9 5             9  5 5 -

您的算法是正確的,但在實現中存在一些錯誤。 當您的循環從 i=2 開始時,您將跳過 C[1] 處的值。 由於您在 F 數組中包含 0 個硬幣盒,因此 F[n] 的大小必須為 n+1 才能存在。 通過上述更正,我們得出:

int max(int a, int b) {
  if(a > b) return a;
  return b;
}

int coin_row(int* C, int n) {
  if(n==1) return C[0];
  if(n==2) return max(C[0],C[1]);

  int F[n+1], i;
  F[0] = 0; F[1] = C[0];

  for(i = 2 ; i <= n + 1 ; i++) {
    F[i] = max(C[i-1] + F[i-2], F[i-1]);
  }
  return F[n];
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM