Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.01.2013, 20:36   #1
LVM
 
Регистрация: 28.01.2013
Сообщений: 7
Вопрос задача Работа банкомата

Купюры номиналом [4]= {10, 20, 50, 100};
количество купюр[4]={20,20,20,20};
клиент вводит сумму. условия:
1. проверить кратна ли она 10
2. сумма меньше 5 000

Показать клиенту информацию о выдаче денег. Списать деньги из массива "количество купюр".

при этом если количество купюр каждого номинала заканчивается - выдавать деньги меньшим номиналом, пока в банкомате не закончатся купюры.


то, что у меня получилось написать:
Код:
{
setlocale(LC_ALL, "rus");

int CassNom[4]={10,20,50,100};//номинал
int CassKol[4]={10,10,10,10};//количество купюр соответствующего номинала
int summa;//сумма, которую вводит пользователь



cout<<"Введите сумму кратную 10: ";
cin>>summa;
if (summa%10!=0){//если сумма не кратна 10-ти:
	do{
	cout<<"Банкомат не может выдать данную сумму! Введите сумму кратную 10: ";
	cin>>summa;
	}
while (summa%10!=0);}//пока сумма не будет кратна 10-ти
else
if (summa>5000){//если сумма больше 5000 банкомат не выдает
	do {
cout<<"Слишком большая сумма! \n Введите сумму не больше 5 000 грн. кратную 10.\n Или обратитесь в кассу!";
	cin>>summa;}
	while (summa>5000);//пока сумма не будет меньше 5000
}

if (summa%100==0&&summa<1000){//если сумма кратна 100 и меньше 1000
CassKol[3]=CassKol[3]-(summa/100%10);//количество купюр номиналом 100грн. уменьшается на количество сотен в сумме
}
else if (summa%1000==0&&summa<=5000){
CassKol[3]=CassKol[3]-(summa/100%100);
}

//else  if(summa%100==50&&summa<1000){
//CassKol[2]=CassKol[2]-1;
//}

for(int i=0; i<4; i++){
cout<<CassKol[i]<<" ";
}


}




еще примечание: мы изучили только темы: объявление переменных, if, else, switch, break, continue, do while, for, массивы.

Помогите, пожалуйста, решить задачу. Совсем запуталась с ней

Последний раз редактировалось Stilet; 28.01.2013 в 21:28.
LVM вне форума Ответить с цитированием
Старый 29.01.2013, 12:30   #2
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Первый совет: чтобы меньше путаться, выделяйте функции (если Вы их не проходили - советую изучить самостоятельно, это очень важная вещь, всяко важнее switch, и довольно несложная). Возьмём Ваш код и чуть преобразуем:
Код:
int GetUserSum(void){ //Получаем требуемую сумму со всеми ограничениями
  int summa;//сумма, которую вводит пользователь

  cout<<"Введите сумму кратную 10: ";
  cin>>summa;
  if (summa%10!=0){//если сумма не кратна 10-ти:
	do{
	cout<<"Банкомат не может выдать данную сумму! Введите сумму кратную 10: ";
	cin>>summa;
	}
    while (summa%10!=0);}//пока сумма не будет кратна 10-ти
  else
  if (summa>5000){//если сумма больше 5000 банкомат не выдает
	do {
      cout<<"Слишком большая сумма! \n Введите сумму не больше 5 000 грн. кратную 10.\n Или обратитесь в кассу!";
	cin>>summa;}
	while (summa>5000);//пока сумма не будет меньше 5000
  }

  return summa; //Гарантируется, что возвращаемая функцией сумма - "правильная"
}

//Далее, если сумма превышает 3600 - мы не сможем её выдать,
// в банкомате нет столько денег. Условие тривиально, но его
// тоже хорошо вынести в отдельную функцию, по причинам, указанным далее
bool SumIsTooBig(int sum){
  if(sum > 3600) return true;
  else return false;
}

//Наконец, ещё одна задача - взять (оставшуюся) сумму, номинал купюр, количество купюр
//и сказать - сколько купюр этого номинала нужно выдать.
//В предположении, что купюр крупнее (уже) нет или они слишком крупные
int BanknotesNumber(int remSum, int nominal, int number){
  //Если сумма больше совокупной суммы купюр - выдать все
  if(remSum > nominal*number) return number;
  //else не нужен - подумайте, почему
  return remSum/nominal;
}

int main(void){
setlocale(LC_ALL, "rus");

int CassNom[4]={10,20,50,100};//номинал
int CassKol[4]={20,20,20,20};//количество купюр соответствующего номинала
//Эй, а почему тут было 10, хотя в условии 20?
//Нам также нужен ТРЕТИЙ массив - то, какие купюры мы выдаём:
int GivenKol[4] = {0, 0, 0, 0};

int summa = GetUserSum();//сумма, которую ВВЁЛ пользователь

if(SumIsTooBig(summa)){
  //endl - "конец строки (переход на новую строку)".
  cout << "Извините, в банкомате недостаточно наличности :(" << endl;
  //Заканчиваем выполнение
  return 0;
}

//Запутались? Хорошая идея зачеркнуть всё и написать заново
/*if (summa%100==0&&summa<1000){//если сумма кратна 100 и меньше 1000
CassKol[3]=CassKol[3]-(summa/100%10);//количество купюр номиналом 100грн. уменьшается на количество сотен в сумме
}
else if (summa%1000==0&&summa<=5000){
CassKol[3]=CassKol[3]-(summa/100%100);
}*/

//От крупного номинала к мелкому,
for(int i=3; i>=0; --i){
  //Определяем, сколько банкнот надо отстегнуть
  GivenKol[i] = BanknotesNumber(summa, CassNom[i], CassKol[i]);
  //Убираем их из кассеты банкомата
  CassKol[i] = CassKol[i] - GivenKol[i];
  //И УМЕНЬШАЕМ сумму к выдаче
  summa = summa - CassNom[i] * GivenKol[i];
}

//Самопроверка: если всё было правильно, summa должна стать нулём
if(summa != 0){
  cout << "Ой, что-то не работает!" << endl;
}
//else  if(summa%100==50&&summa<1000){
//CassKol[2]=CassKol[2]-1;
//}

//По условию задачи надо вроде как вывести количества и номиналы купюр
for(int i=0; i<4; i++){
  if(GivenKol[i] == 0) continue; //Мы же не хотим писать "выдано 0 купюр"?
  cout << "Выдано "<< GivenKol[i] << " купюр номинала " << CassNom[i] << endl;
}

}
Так работает... почти. Проблема в том, что, если ввести вначале 6000, а потом 111, Ваша программа это "проглотит". Но, если Вы выделили код проверки в отдельную функцию, нам нужно править только её:
Код:
int GetUserSum(void){ //Получаем требуемую сумму со всеми ограничениями
  int summa;//сумма, которую вводит пользователь

  cout<<"Введите сумму кратную 10: ";
  cin>>summa;
  //Соединяем условия и загоняем в простой while:
  while(summa%10!=0 || summa>5000){
    //Разбираемся, в чём там проблема
    if (summa%10!=0) {//если сумма не кратна 10-ти:
	cout<<"Банкомат не может выдать данную сумму! Введите сумму кратную 10: " << endl;
    }
    else if (summa>5000){//если сумма больше 5000 банкомат не выдает
      cout<<"Слишком большая сумма! \n Введите сумму не больше 5 000 грн.\n Или обратитесь в кассу!" << endl;
    }
    else { //Эй, а как мы сюда-то попадём? См. ниже
      cout << "С введённой Вами суммой что-то не так. Пожалуйста, введите другую сумму" << endl;
    }
    cin>>summa;
  } //Вот теперь, если мы вышли из while - всё в порядке

  return summa; //Гарантируется, что возвращаемая функцией сумма - "правильная"
}
Поскольку в действительности ограничения вида "сумма не более 5000" имеют свойство меняться, полезно вынести условие (summa%10!=0 || summa>5000) в отдельную функцию, аналогичную SumIsTooBig:
Код:
bool SumBreaksRules(int summa){
  if(summa%10!=0 || summa>5000) return true;
  return false;
}
Abstraction вне форума Ответить с цитированием
Старый 29.01.2013, 12:30   #3
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Далее, стоит изменить SumIsTooBig так, чтобы она использовала состояние кассы, а не "волшебное" число 3600:
Код:
bool SumIsTooBig(int sum, int cassNom[4], int cassKol[4]){
  int maxSum = 0;
  for(int i=0; i<4; ++i) maxSum = maxSum + cassNom[i]*cassKol[i];
  
  if(sum > maxSum) return true;
  return false;
}
Вызов также меняется:
Код:
if(SumIsTooBig(summa, CassNom, CassKol)){
//...
И ещё одно важное улучшение, касающееся "магических чисел": число 4 у нас "расползлось" по всей программе. Если придётся добавить пятый тип купюр, его придётся везде менять, и хоть где-нибудь, да забудем. Поэтому, перед всеми функциями, пишем:
Код:
const int N = 4;
Окончательно:
Код:
 const int N = 4;

bool SumBreaksRules(int summa){
  if(summa%10!=0 || summa>5000) return true;
  return false;
}

int GetUserSum(void){ //Получаем требуемую сумму со всеми ограничениями
  int summa;//сумма, которую вводит пользователь

  cout<<"Введите сумму кратную 10: ";
  cin>>summa;
  //Пока сумма неправильная - капаем пользователю на мозги:
  while(SumBreaksRules(summa)){
    //Разбираемся, в чём там проблема
    if (summa%10!=0) {//если сумма не кратна 10-ти:
	cout<<"Банкомат не может выдать данную сумму! Введите сумму кратную 10: " << endl;
    }
    else if (summa>5000){//если сумма больше 5000 банкомат не выдает
      cout<<"Слишком большая сумма! \n Введите сумму не больше 5 000 грн.\n Или обратитесь в кассу!" << endl;
    }
    else { //Если нарушено неучтённое правило
      cout << "С введённой Вами суммой что-то не так. Пожалуйста, введите другую сумму" << endl;
    }
    cin>>summa;
  } //Вот теперь, если мы вышли из while - всё в порядке

  return summa; //Гарантируется, что возвращаемая функцией сумма - "правильная"
}

//Далее, если в банкомате нет столько денег - значит, облом.
bool SumIsTooBig(int sum, int cassNom[N], int cassKol[N]){
  int maxSum = 0;
  for(int i=0; i<N; ++i) maxSum = maxSum + cassNom[i]*cassKol[i];
  
  if(sum > maxSum) return true;
  return false;
}

//Наконец, ещё одна задача - взять (оставшуюся) сумму, номинал купюр, количество купюр
//и сказать - сколько купюр этого номинала нужно выдать.
//В предположении, что купюр крупнее (уже) нет или они слишком крупные
int BanknotesNumber(int remSum, int nominal, int number){
  //Если сумма больше совокупной суммы купюр - выдать все
  if(remSum > nominal*number) return number;
  //else не нужен - подумайте, почему
  return remSum/nominal;
}

int main(void){
  setlocale(LC_ALL, "rus");

  int CassNom[N]={10,20,50,100};//номинал
  int CassKol[N]={20,20,20,20};//количество купюр соответствующего номинала
  //Эй, а почему тут было 10, хотя в условии 20?
  //Нам также нужен ТРЕТИЙ массив - то, какие купюры мы выдаём:
  int GivenKol[N] = {0, 0, 0, 0};

  int summa = GetUserSum();//сумма, которую ВВЁЛ пользователь

  if(SumIsTooBig(summa, CassNom, CassKol)){
    //endl - "конец строки (переход на новую строку)".
    cout << "Извините, в банкомате недостаточно наличности :(" << endl;
    //Заканчиваем выполнение
    return 0;
  }

  //От крупного номинала к мелкому,
  for(int i=N-1; i>=0; --i){
    //Определяем, сколько банкнот надо отстегнуть
    GivenKol[i] = BanknotesNumber(summa, CassNom[i], CassKol[i]);
    //Убираем их из кассеты банкомата
    CassKol[i] = CassKol[i] - GivenKol[i];
    //И УМЕНЬШАЕМ сумму к выдаче
    summa = summa - CassNom[i] * GivenKol[i];
  }

  //Самопроверка: если всё было правильно, summa должна стать нулём
  if(summa != 0){
    cout << "Ой, что-то не работает!" << endl;
  }

  //По условию задачи надо вроде как вывести количества и номиналы купюр
  for(int i=0; i<N; i++){
    if(GivenKol[i] == 0) continue; //Мы же не хотим писать "выдано 0 купюр"?
    cout << "Выдано "<< GivenKol[i] << " купюр номинала " << CassNom[i] << endl;
  }

}
Abstraction вне форума Ответить с цитированием
Старый 29.01.2013, 14:53   #4
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Код:
#include <iostream>
int main() {
  const int n = 4;
  int CassNom[n]={10,20,50,100};//номинал
  int CassKol[n]={10,10,10,10};//количество купюр соответствующего номинала
  int summa;//сумма, которую вводит пользователь
  int kol; //! количество купюр
  do {
    std::cin >> summa;
    if (summa < 0 || summa > 5000 || 0 != summa % 10) {
      std::cout << "wrong data" << std::endl;
      continue;
    }
  } while (false);
  
  for (int i = 0; i < n; ++i) {
    kol = summa / CassNom[i];
    kol = CassKol[i] < kol ? CassKol[i] : kol;
    std::cout << kol << " x " << CassNom[i] << std::endl;
    CassKol[i] -= kol;
    summa -= kol * CassNom[i];
  }
  
  return 0;
}
rrrFer вне форума Ответить с цитированием
Старый 29.01.2013, 16:58   #5
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

1) continue в do {...} while(false) приводит к выходу из цикла (continue перемещает на конец итерации цикла, затем проверяется условие и...).
2) Вы идёте от младших купюр к страшим, так что 100 выдадите как 10 десяток, а 110 выдать не сможете вовсе, причём этого даже не обнаружите.
Abstraction вне форума Ответить с цитированием
Старый 29.01.2013, 18:04   #6
LVM
 
Регистрация: 28.01.2013
Сообщений: 7
По умолчанию

Спасибо за помощь!!! Вы, наверное, потратили много времени на эту задачу!

сейчас засяду и начну вникать и "понимать", что к чему.
LVM вне форума Ответить с цитированием
Старый 29.01.2013, 19:06   #7
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

окей ))
Код:
#include <iostream>
int main() {
  const int n = 4;
  int CassNom[n]={10,20,50,100};//номинал
  int CassKol[n]={10,10,10,10};//количество купюр соответствующего номинала
  int summa;//сумма, которую вводит пользователь
  int kol; //! количество купюр
  
  do {
    std::cin >> summa;
    if (summa > 0 && summa < 5000 && 0 == summa % 10) 
      break;
    std::cout << "wrong data" << std::endl;
  } while (true);
  
  for (int i = n - 1; i >= 0; --i) {
    kol = summa / CassNom[i];
    kol = CassKol[i] < kol ? CassKol[i] : kol;
    std::cout << kol << " x " << CassNom[i] << std::endl;
    summa -= kol * CassNom[i];
  }
  
  return 0;
}
Цитата:
а 110 выдать не сможете вовсе, причём этого даже не обнаружите.
в общем виде задача не решается жадным алгоритмом, поэтому о том, что что-то там выдать нельзя лучше не вспоминать Если ТС не будет номиналы менять - то да, сойдет (они тут хитро подогнаны).
rrrFer вне форума Ответить с цитированием
Старый 29.01.2013, 19:21   #8
LVM
 
Регистрация: 28.01.2013
Сообщений: 7
По умолчанию

Abstraction, мне было весело читать Ваш развернутый ответ

Не могу поверить, что нам задали такую сложную задачу. Я начала изучать программирование только 3 месяца назад!

мне надо еще несколько раз все пречитать, чтобы понять
LVM вне форума Ответить с цитированием
Старый 30.01.2013, 10:49   #9
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Я начала изучать программирование только 3 месяца назад!
Никогда не видели книжек "изучи C++ за 21 день"?
Цитата:
Не могу поверить, что нам задали такую сложную задачу.
Ну, функции проверок можно упростить до:
Код:
int GetUserSum(void){ //Получаем требуемую сумму со всеми ограничениями
  int summa;//сумма, которую вводит пользователь

  cout<<"Введите сумму кратную 10 и меньше 5000: ";
  cin>>summa;
  if(SumBreaksRules(summa)){
    cout << "Вы ввели неправильную сумму. Запустите программу ещё раз." << endl;
    return 0; //Не выдаём нифига
  } 
  return summa; //Гарантируется, что возвращаемая функцией сумма - "правильная"
}

bool SumIsTooBig(int sum, int cassNom[N], int cassKol[N]){
  //Считаем, что нам никогда-никогда не введут слишком большой суммы
  return false;
}
Но поскольку это именно отдельные функции, которые можно модифицировать независимо, их упрощение не является средством упрощения программы, зато открывает двери ошибкам.
Вот кстати: сейчас, если пользователь введёт отрицательное число, кратное 10, произойдёт странное. В качестве самостоятельного задания - подумайте, как предотвратить такую проблему.

Вообще (к слову о простых и сложных программах), один тестер упоминал о такой задаче на собеседовании:
Цитата:
Есть программа, аргументом принимающая число N и печатающая числа от 1 до этого N. Как её можно оттестировать?
В обсуждении набралось где-то полтора десятка разных тестов, потенциально обнаруживающих ошибки.
Abstraction вне форума Ответить с цитированием
Старый 30.01.2013, 11:51   #10
LVM
 
Регистрация: 28.01.2013
Сообщений: 7
По умолчанию

))))) с++ за 21 день - это не для меня! не могу выделить больше 1,5 часа в день для этого дела! и то не каждый день получается позаниматься!

может Вы будете так добры и скинете мне ссылку, где можно почитать эту книгу
LVM вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Задача по C++ работа с массивом Phangorn Помощь студентам 0 26.12.2011 21:26
Хитрая проблема/задача/работа awarebeaver Фриланс 1 20.10.2011 13:53
Задача на C++. Работа с классами. HenryL Фриланс 4 10.11.2010 19:52
Задача. Работа с псевдослучайными последовательностями (ПСП). Работа с цветом. 0101 Помощь студентам 3 17.12.2009 23:57
Работа со строками. Задача Memfis_nya Общие вопросы C/C++ 4 16.11.2008 18:42