2010-10-13 76 views
3

你好,我試圖創建一個algorythm,找出有多少種方式我可以得到變回。 但我只是無法得到實施權,我不斷得到4,我應該得到6,我只是不明白爲什麼。硬幣更改,只是不能正確地得到它

這是我在C#實現,它是從僞創建http://www.algorithmist.com/index.php/Coin_Change

 private static int[] S = { 1, 2, 5 }; 
     private static void Main(string[] args) 
     { 
      int amount = 7; 
      int ways = count2(amount, S.Length); 
      Console.WriteLine("Ways to make change for " + amount + " kr: " + ways.ToString()); 
      Console.ReadLine(); 
     }  
static int count2(int n, int m) 
     { 
     int[,] table = new int[n,m]; 

     for (int i = 0; i < n; i++) 
     { 
      for(int j = 0; j < m; j++) 
      { 
       // Rules 
       // 1: table[0,0] or table[0,x] = 1 
       // 2: talbe[i <= -1, x] = 0 
       // 3: table[x, j <= -1] = 0 

       int total = 0; 

       // first sub-problem 
       // count(n, m-1) 
       if (i == 0) // rule 1 
        total += 1; 
       else if (i <= -1) // rule 2 
        total += 0; 
       else if (j - 1 <= -1) 
        total += 0; 
       else 
        total += table[i, j-1]; 

       // second sub-problem 
       // count(n-S[m], m) 
       if (j - 1 <= -1) // rule 3 
        total += 0; 
       else if (i - S[j - 1] == 0) // rule 1 
        total += 1; 
       else if (i - S[j - 1] <= -1) // rule 2 
        total += 0; 
       else 
        total += table[i - S[j-1], j]; 

       table[i, j] = total; 
      } 
     } 
     return table[n-1, m-1]; 
    } 
+0

對不起,這是要0..n和0..m – Androme 2010-10-14 00:07:56

回答

1

這是算法的工作順序。按綠色的「播放」箭頭運行它。 http://www.exorithm.com/algorithm/view/make_change

我認爲主要問題是算法循環應該從-1開始。我認爲它會遞歸地寫得更清楚,但這是一個有趣的練習。

2

如果你解釋你的算法是如何工作的這將是有益的。當沒有評論和變量被命名只是n,m,i,這是很難理解的目的。例如,在迭代各種類型的硬幣時,您應該使用更多的描述性名稱,例如coinType

但是,有些地方看起來對我很可疑。例如,您的變量ij會重複範圍爲1 .. m1 .. n的值 - 它們始終是正數。這意味着,你的規則2和3永遠不會運行:

// ... 
    else if (i <= -1)  // <- can never be 'true' 
    total += 0; 
    else if (j - 1 <= -1) // <- 'true' when 'j == 0' 
// ... 
    if (j - 1 <= -1)  // <- can never be 'true' 
// ... 

i是永遠不會小於或等於-1j同樣。

+0

對不起,這是要0..n和0..m:D – Androme 2010-10-13 23:41:53

+0

@DoomStone:即使'i'可能是'0'那麼'i <= -1'永遠不會發生。如果條件只處理一些角落案例(單個元素),那麼你可以寫'if(i == 0)...'使其可讀。 – 2010-10-14 00:10:12

+0

這是事實,但它不應該對結果產生影響。 – Androme 2010-10-14 00:23:41

1

一些觀察。

1)如果您將count函數從僞代碼移動到單獨的子例程中,它會使您的代碼更加簡單(並且不易出錯)。像這樣的東西(基於僞代碼從您的鏈接)

func count(table, i, j) 
    if (i == 0) 
    return 1 
    if (i < 0) 
    return 0 
    if (j <= 0 and i >= 1) 
    return 0 

    return table[i][j] 
end 

然後,你可以做

table[i][j] = count(table, i, j - 1) + count(table, i - S[j], j) 

在你的內部循環。

2)在count2中,您的第一個循環將發生n - 1次。這意味着,對於n == 1,您將不會進入循環體,並且不會找到任何解決方案。內循環相同:如果只有一枚硬幣,則不會找到任何解決方案。

+0

在我給你的代碼中有一個miske,它是0 .. n和0 .. mi已經修復了第一篇文章中的代碼 – Androme 2010-10-13 23:50:06

+0

@DoomStone不是聽起來迂腐,但我真的認爲擺脫了spagetti代碼在你的內部循環將幫助你找到一個錯誤。 – 2010-10-14 00:38:23

+0

我已經做了這個,但我仍然有同樣的問題 – Androme 2010-10-14 00:40:59

1

我相信你的意思是表格[我,j]存儲的方式,以只使用硬幣{0,1,2,...,j - 1}的價值完全達到美分的數量。

本質上,while循環的內部部分是說表[i,j]應該等於達到i的值時不使用任何硬幣j的方法的數量,加上實現數值的方法的數量我使用至少一個價值S [j]的硬幣。因此,除邊界情況外,其值爲表[i,j - 1] +表[i - S [j],j];總和的第一部分是使用沒有價值S [j]的硬幣到達我的方法的數量,第二部分是使用至少一個值S [j]的硬幣到達i的方法的數量。

嘗試改變:

 // second sub-problem 
     // count(n-S[m], m) 
     if (j - 1 <= -1) // rule 3 
      total += 0; 
     else if (i - S[j - 1] == 0) // rule 1 
      total += 1; 
     else if (i - S[j - 1] <= -1) // rule 2 
      total += 0; 
     else 
      total += table[i - S[j-1], j]; 

到:

 // second sub-problem 
     // count(n-S[m], m) 
     if (i - S[j] == 0) // rule 1 
      total += 1; 
     else if (i - S[j] < 0) // rule 2 
      total += 0; 
     else 
      total += table[i - S[j], j]; 

僅供參考,它是標準的寫類似(j < 0)而不是(j < = -1)。

+0

如果我改變if(j - 1 <= -1)if(j <= -1)它會得到一個超出界限的錯誤。 – Androme 2010-10-14 00:28:31

+0

它應該是s [j-1],因爲S從0開始並轉到m-1 – Androme 2010-10-14 00:29:11

+0

我不認爲你需要那個測試。查看編輯。變量j永遠不會小於0. – jonderry 2010-10-14 00:35:13

4

出於絕對的深夜無聊(是的,這肯定需要精煉)......它一次使用遞歸,linq和yield,並且具有與代碼行數一樣多的括號,所以我相當不滿意它...

static IEnumerable<List<int>> GetChange(int target, IQueryable<int> coins) 
    { 
     var availableCoins = from c in coins where c <= target select c; 
     if (!availableCoins.Any()) 
     { 
      yield return new List<int>(); 
     } 
     else 
     { 
      foreach (var thisCoin in availableCoins) 
      { 
       foreach (var result in GetChange(target - thisCoin, from c in availableCoins where c <= thisCoin select c)) 
       { 
        result.Add(thisCoin); 
        yield return result; 
       } 
      } 
     } 
    } 
+0

這是很好,簡潔,你是對的,一次使用各種技術。然而,如果沒有給定的硬幣解決方案,它將計算關閉的解決方案變小。例如目標20,硬幣3和6產生的組合增加到18個。因此使用這隻需要檢查結果加起來到目標。 – goodeye 2013-11-18 02:02:27

+0

實際上,由於這是循環所有硬幣到目標,這是一個正確和不正確的解決方案的組合。例如具有6,5的目標18給出666,566,556,555。 – goodeye 2013-11-18 16:48:24