Chào mọi người. Mình có đang làm 1 problem sau: http://ntucoder.net/Problem/Details/5621
Hướng giải của mình sẽ là dùng quay lui để giải như sau:
- Đầu tiên, ta sinh 1 dãy nhị phân có độ dài bằng số chữ số của x + số chữ số của y (tối đa là 18 chữ số theo giới hạn của đề) bằng quay lui.
- Ta sẽ quy ước trong dãy nhị phân, ký tự 0 nghĩa là lấy chữ số đầu tiên của x từ trái sang bỏ vào mảng kết quả
result[]
, ký tự 1 nghĩa là lấy chữ số đầu tiên của y tù trái sang bỏ vào mảng kết quảresult[]
. (như thế chúng sẽ vẫn giữ nguyên thứ tự ghi ghép số) - Vì quy ước trên, những dãy nhị phân có tổng số ký tự 0 khác số chữ số của x hoặc tổng số ký tự 1 khác số chữ số của y thì sẽ sai, ta không xét đến.
- Sau cùng, ta sẽ tìm min và max của mảng kết quả
result[]
, đó chính là kết quả trả về của chương trình.
VD: x = 13, y = 26
Ta sẽ sinh dãy nhị phân có độ dài = 4 mà số ký tự 0 là 2 và số ký tự 1 là 2:
0011
0101
0110
1001
1010
1100
Với 0011
ta sẽ có giá trị: 1326
Với 0101
ta sẽ có giá trị: 1236
Với 0110
ta sẽ có giá trị: 1263
Với 1001
ta sẽ có giá trị: 2136
Với 1010
ta sẽ có giá trị: 2163
Với 1100
ta sẽ có giá trị: 2613
Dễ thấy, trong 6 giá trị tìm được, GTNN là 1236
và GTLN là 2613
, đây chính là output của thuật toán.
Dựa vào ý tưởng trên, mình code như sau: https://ideone.com/LQA9cw
#include <iostream>
#include <cmath> // pow() and log10()
#include <cstring> // memset()
#include <algorithm> // std::min_element() and std::max_element()
using namespace std;
// Problem: http://ntucoder.net/Problem/Details/5621
int arr[18]; // Store the binary sequence
int result[262144]; // (=2^18) Store the possible results of number z
int a, b, na, nb, _index = 0, n = 0;
/* a and b is the 2 numbers of input. na is the number of digit of a, nb is the number of
digit of b, _index is the index of array result[], n is the number of elements of result[]*/
void Analyze(int a[])
{
/* "_na" is used with pow() of base 10 and mod 10 to take the first digit of "a" from
the left to the right. So is "_nb".
For instance: a = 584 => na = 3 => _na = 2 => (584 / 10^2) % 10 = 5 is the first digit
of a from the left to the right.
*/
int _na = na - 1, _nb = nb - 1, temp = na + nb - 1;
for (int i = 0; i < (na + nb); ++i) {
if (a[i] == 0) {
int digit = static_cast<int>(::a/pow(10, _na--)) % 10;
result[_index] += digit * pow(10, temp--);
}
else {
int digit = static_cast<int>((::b)/pow(10, _nb--)) % 10;
result[_index] += digit * pow(10, temp--);
}
}
++_index; // update the index of result[] for the next assignments.
}
// Backtracking
void ListBinary(int i)
{
// na + nb is the length of the binary sequence.
if (i == (na + nb)) {
/* Count if the number of value 0 in the binary sequence is equal to the length of
a and the number of value 1 in the binary sequence is equal to the length of b. */
int zero = 0, one = 0;
for (int i = 0; i < (na + nb); ++i) {
if (arr[i] == 0)
++zero;
else ++one;
}
/* If the binary sequence is appropriate, then we will use it to create a number
and put into the result[] */
if (zero == na && one == nb) {
++n;
Analyze(arr);
}
}
else {
arr[i] = 0;
ListBinary(i + 1);
arr[i] = 1; // backtrack
ListBinary(i + 1);
}
}
int main()
{
memset(result, 0, 262144);
cin >> a >> b;
na = (int)log10(a) + 1;
nb = (int)log10(b) + 1;
ListBinary(0);
cout << *min_element(result, result + n) << endl << *max_element(result, result + n);
return 0;
}
Vì code khá dài nên mình chú thích từng đoạn cho mọi người đọc dễ hiểu.
Khi submit lên trang NTUcoder thì code bị sai ở test số 9 (tức là có bug).
Mình tìm hoài không thấy nên post lên đây nhờ các cao nhân giúp đỡ ạ!
Xin cảm ơn.