#c #algorithm #recursion
#c #алгоритм #рекурсия
Вопрос:
//amt = amount of cents to get change for
//onhand = array of available coins . Ex: {3, 0, 1, 0} = 3 quart, 0 dime, 1 nickel, 0 pennies
//denoms = {25, 10, 5, 1}
//ndenoms = 4 ; i.e the number of different denominations
// thechange = array of change. Ex: if amt = 80, then one possible thechange = {3, 0, 1, 0} b/c 3*25 1*5 = 80 cents
int i = 0;
void makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
if ( (denoms[i] * onhand[i]) > amt)
{
onhand[i]--; // # of coins is too much, decrement and try again
makechange(amt, onhand, denoms, ndenoms, thechange); // try agan
}
thechange[i] = onhand[i]; //found #of coins
amt = amt - denoms[i]*onhand[i]; // get remaining amount from change
i ;
if (amt != 0) // we're not done with change so move on to next denomination
{
makechange(amt, onhand, denoms, ndenoms, thechange);
}
else if (amt == 0) // we're done with the change so all the other # coins = 0
{
for (int j = i; j < amt; j )
{
thechange[j] = 0;
}
}
}
Now, down in main when I actually call the function prototype and print out the result
//
makechange(amt, onhand, denoms, ndenoms, thechange);
for (int k = 0; k < ndenoms; k )
{
cout << thechange[i] << " ";
}
//
Я получаю сообщение об ошибке.
Этот алгоритм кажется мне разумным, кто-нибудь знает, почему он продолжает сбоить?
Правильно ли я использовал рекурсию здесь?
Комментарии:
1. Как происходит сбой? Вы получаете сообщение об ошибке, когда это происходит? И что это за язык?
2. Я использую C и компилирую с devc
3. Всякий раз, когда я компилирую и запускаю, я получаю «change.exe перестал работать » итак, я предполагаю, что ошибка seg или что-то в этом роде?
4. Тег изменен на
c
для согласованности с языком и компилятором, используемым OP
Ответ №1:
Если вы вызовете makechange
дважды, во второй раз это не сработает, потому что глобальная переменная i
будет неправильной.
Также, что должно произойти, если вы попытаетесь makechange
и у вас недостаточно изменений для этого?
Аналогично, что произойдет, если у вас есть 3 четвертака и 3 десятицентовика, и вас просят внести 80 центов сдачи? Ваш алгоритм будет использовать все 3 квартала, а затем застрянет.
Комментарии:
1. @ted-stevens: Ваш алгоритм предполагает, что
i
начинается с 0. Если выmakechange
уже вызывали, значение больше не равно 0, и вы никогда не увидите свое первое обозначение.
Ответ №2:
вы имели в виду
for (int k = 0; k < ndenoms; k ) { cout << thechange[k] << " "; }
небольшая опечатка стала возможной благодаря использованию глобальной переменной i.
также
for (int j = i; j < amt; j ) { thechange[j] = 0; }
Я думаю, вы имели в виду
for (int j = i; j < ndenoms; j )
в зависимости от конечного значения amt это приведет к завершению работы с концом массива, что приведет к сбою.
вы можете решить это проще без рекурсии. обязательно ли использовать рекурсию для назначения? если нет, попробуйте это:
int makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
for (int i=0; i < ndenoms amp;amp; amt > 0; i )
{
while (onhand[i] > 0 amp;amp; denoms[i] <= amt)
{
onhand[i]--; // use one coin
thechange[i] ;
amt -= denoms[i];
}
}
return amt; // this is the amount you owe if you dont have enough on hand
}
Комментарии:
1. ^ спасибо, но даже после этого он все еще вылетает. Кто-нибудь может скопировать и вставить мой код и попробовать его, пожалуйста?
2. Попробуйте добавить операторы печати при входе и выходе из makechange. Возможно, вы поймете, что не так, когда сможете увидеть контекст сбоя.
3. также вы не проверяете наличие i> = ndenoms в качестве условия выхода. Вы можете вывести нижний индекс за пределы диапазона после последнего i , если не будете осторожны.
4. ^ Почему алгоритм зацикливается вечно?
5. Мне не нужна инструкция exit, не так ли? Функция больше не будет вызывать себя один раз (amt == 0) и завершать остальную часть main. Так разве этого недостаточно?
Ответ №3:
Я внес изменения, упомянутые shsmith, и вот модифицированная и полная программа на c .
#include <iostream>
using namespace std;
int i = 0;
void makechange(int amt, int *onhand, int *denoms, int ndenoms, int *thechange)
{
if ( (denoms[i] * onhand[i]) > amt)
{
onhand[i]--; // # of coins is too much, decrement and try again
makechange(amt, onhand, denoms, ndenoms, thechange); // try agan
}
thechange[i] = onhand[i]; //found #of coins
amt = amt - denoms[i]*onhand[i]; // get remaining amount from change
i ;
if (amt != 0) // we're not done with change so move on to next denomination
{
makechange(amt, onhand, denoms, ndenoms, thechange);
}
else if (amt == 0) // we're done with the change so all the other # coins = 0
{
for (int j = i; j < ndenoms; j )
{
thechange[j] = 0;
}
}}
int main(){
//Now, down in main when I actually call the function prototype and print out the result
int amt = 80, onhand[] = {3, 0, 1, 0}, denoms[] = {25, 10, 5, 1}, ndenoms = 4, thechange[4];
makechange(amt, onhand, denoms, ndenoms, thechange);
for (int k = 0; k < ndenoms; k )
{
cout << thechange[k] << " ";
}
cout << "n";
return 0;}
Этот код отлично работает на моей машине. Я скомпилировал его с помощью Cygwin.
Примечание: Этот алгоритм будет работать, только если у вас есть монеты номинала более или менее корректно на руках. Если в наличии недостаточно монет, то у рекурсивного метода нет выхода, потому что 'amt' никогда не станет равным нулю. В то же время вы никогда не проверяете значение 'i', находится ли оно в пределах 'ndenoms'. Это также может привести к ошибкам вне границ, которые могут привести к неправильному завершению вашей программы.