[PHP cơ bản] Giải bài toán ATM trả về số lượng tờ tiền cụ thể
1. Cho bài toán rút tiền ATM như sau:
-
Nhập vào số tờ tiền trong máy ATM:
- Số tờ tiền 500k có trong ATM
- Số tờ tiền 200k có trong ATM
- Số tờ tiền 100k có trong ATM
- Số tờ tiền 50k có trong ATM
-
Nhập vào số tiền muốn rút và in ra số lượng các tờ tiền với các mệnh giá khác nhau.
-
Ví dụ: Ví dụ:
- Số tờ tiền 500k có trong ATM: 2
- Số tờ tiền 200k có trong ATM: 2
- Số tờ tiền 100k có trong ATM: 2
- Số tờ tiền 50k có trong ATM: 2
=> Nhập số tiền muốn rút: 2000k => ATM ko đủ tiền
=> Nhập số tiền muốn rút: 1500k => 500K - 2 tờ, 200k - 2 tờ, 100k - 1 tờ
=> Nhập số tiền muốn rút: 1555k => Số tiền muốn rút phải là bội số của 50
2. Code demo (Gặp Error )
- Đầu tiên khởi tạo 1 file có tên index.php/index.html gồm form chứa input để nhập vào số tờ tiền.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="atm.php" method="POST">
Nhập vào số tiền ATM đang có: <br><br>
Số tờ 500k: <input type="number" name="500"><br><br>
Số tờ 200k: <input type="number" name="200"><br><br>
Số tờ 100k: <input type="number" name="100"><br><br>
Số tờ 50k: <input type="number" name="50"><br><br>
Nhập vào số tiền cần rút: <br><input type="text" name="input-money"><br><br>
<input type="submit" value="Nhận tiền">
</form>
</body>
</html>
- Tạo file có tên atm.php để gọi vào xử lý form trong file index.php.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
//get money input from customer - nhận số tiền mà khách hàng nhập vào
$getMoney = $_POST["input-money"];
//get money denominations in ATM - nhận mệnh giá tiền trong ATM
$atm500 = $_POST["500"];
$atm200 = $_POST["200"];
$atm100 = $_POST["100"];
$atm50 = $_POST["50"];
//Sum money in ATM - Tổng tiền trong ATM
$sum = ($atm500 * 500000) + ($atm200 * 200000) + ($atm100 * 100000) + ($atm50 * 50000);
if ($getMoney > $sum) {
echo "ATM không đủ tiền!";
} elseif ($getMoney % 50000 != 0) {
echo "Số tiền nhập vào phải là bội số của 50.";
} else {
if (($getMoney % 500000 == 0) && (floor($getMoney / 500000) <= $atm500)) {
echo "Rút tiền thành công!" .
"<br>Số tờ 500k: " . floor($getMoney / 500000);
} else {
$surplus = $getMoney % 500000;
if (($surplus % 200000 == 0) && (floor($getMoney / 500000) > $atm500) && (floor($getMoney / 200000) <= $atm200)) {
echo "Rút tiền thành công!" .
"<br>Số tờ 500k: " . floor($getMoney / 500000) .
"<br>Số tờ 200k: " . floor($surplus / 200000);
} else {
$surplus1 = $surplus % 200000;
if (($surplus1 % 100000 == 0) && (floor($getMoney / 200000) > $atm200) && (floor($getMoney / 100000) <= $atm100)) {
echo "Rút tiền thành công!" .
"<br>Số tờ 500k: " . floor($getMoney / 500000) .
"<br>Số tờ 200k: " . floor($surplus / 200000) .
"<br>Số tờ 100k: " . floor($surplus1 / 100000);
} else {
$surplus2 = $surplus1 % 100000;
if (($surplus2 % 50000 == 0) && (floor($getMoney / 100000) > $atm100)) {
echo "Rút tiền thành công!" .
"<br>Số tờ 500k: " . floor($getMoney / 500000) .
"<br>Số tờ 200k: " . floor($surplus / 200000) .
"<br>Số tờ 100k: " . floor($surplus1 / 100000) .
"<br>Số tờ 50k: " . floor($surplus2 / 50000);
}
}
}
}
}
?>
</body>
</html>
Kết quả đạt được:
- Đã get được tất cả các input cần có.
- Đã kiểm soát được số tiền nhập vào vượt quá tiền trong ATM.
- Đã kiểm soát được số tiền không phải là bội số của 50.
Error gặp phải
Không thể kiểm soát được số tờ tiền 500k, nếu nhập đúng như ví dụ ở mục 1 thì kết quả trả về luôn vượt quá số tờ đã nhập vào máy ATM.
- Input:
* Output:
Cầu cao nhân chỉ rõ lỗi sai và help me cách giải tối ưu và hợp lý hơn. Cảm ơn trước ạ!
𝓝𝓱ậ𝓽 𝓛𝓪𝓶
2 CÂU TRẢ LỜI
Chỗ sai của bạn là khi tính ra số tờ 500K, bạn đang không có logic để check xem số tờ cần rút có vượt quá số tờ còn lại trong máy ATM hay không.
Thế nên nếu máy chỉ có 2 tờ 500K mà bạn cần rút 3, 4, 5 tờ thì kiểu gì nó cũng chạy vào hàm else
ở cuối cùng, rồi vào trong hàm if
và in ra là 3, 4, 5 tờ.
Thực ra bài toán này bạn có thể giải quyết một cách đơn giản là rút ra số tờ có mệnh giá lớn nhất trong ATM mà không vượt quá số tiền cần rút hoặc rút ra toàn bộ số tờ có mệnh giá lớn nhất còn lại trong ATM, và cứ lặp lại thế cho đến khi rút được hết tiền thì thôi.
Tức sẽ gồm các bước:
- Check xem ATM có đủ tiền để rút không, không đủ thì báo lỗi
- Check xem số tiền cần rút có phải là bội số của 50,000 không, không phải thì báo lỗi
- Rút ra
n
tờ tiền có mệnh giá lớn nhất chưa được tính đến trong ATM, vớin = min(Số tiền cần rút / Mệnh giá tờ tiền lớn nhất, Số tờ có mệnh giá lớn nhất)
. Bạn có thể tưởng tượng thế này. Giả sử cần rút và tờ mệnh giá lớn nhất hiện tại là , thì số tờ expect là 3. Nếu số tờ còn lại là 2 thì ta chỉ rút 2 thôi (), còn nếu số tờ còn lại là 4 thì ta rút 3 (). - Sau khi thực hiện xong bước ở trên thì tính toán lại số tiền còn lại sẽ là
Số tiền cần rút (mới) = Số tiền cần rút (cũ) - n * Mệnh giá của n tờ vừa rút
. Nếu số tiền cần rút mà về0
thì kết thúc quá trình rút tiền, còn không thì tiếp tục lặp lại bước rút tiền ở trên với việc mệnh giá "lớn nhất" mới được chuyển xuống mệnh giá tiếp theo.
Bạn có thể tham khảo đoạn code sau:
$moneyArray = [500000, 200000, 100000, 50000];
$numberOfNotes = [2, 2, 2, 2];
$getMoney = 1500000;
$sum = 0;
for ($i = 0; $i < count($moneyArray); $i++) {
$sum += $moneyArray[$i] * $numberOfNotes[$i];
}
if ($getMoney > $sum) {
echo "ATM không đủ tiền";
} elseif ($getMoney % 50000 != 0) {
echo "Số tiền nhập vào không phải là bội số của 50,000";
} else {
for ($i = 0; $i < count($moneyArray); $i++) {
$numberOfReceivedNote = min($getMoney / $moneyArray[$i], $numberOfNotes[$i]);
$getMoney = $getMoney - $numberOfReceivedNote * $moneyArray[$i];
echo ("Số tờ tiền {$moneyArray[$i]}: $numberOfReceivedNote \n");
if ($getMoney == 0) {
break;
}
}
}
$php ruttien.php
Số tờ tiền 500000: 2
Số tờ tiền 200000: 2
Số tờ tiền 100000: 1
@thangtd90 Cảm ơn bạn nhiều lắm
bạn sai ở chỗ đặt các điều kiện cho if. với giá trị nhập vào là 1500000, thì khi so sánh trong các lệnh if :
floor($getMoney / 200000) <= $atm200
và
floor($getMoney / 100000) <= $atm100)
chắc chắn sẽ không thỏa mãn ( vì bạn lấy toàn bộ 1500000 để chia thay vì san bớt cho tờ 500k) và tự động nhảy đến điều kiện cuối:
if (($surplus2 % 50000 == 0) && (floor($getMoney / 100000) > $atm100))
và tất nhiên nó thỏa mãn, khi đó nó trả về
Số tờ 500k: " . floor($getMoney / 500000) // = 3 là đúng r
còn các biến $surplus, $surplus1 , $surplus2 sẽ ngay từ đầu = 0, do khi bạn gán đầu tiên như:
$surplus = $getMoney % 500000;
đã trả về giá trị = 0 rồi (1500000 % 500000 = 0)