Mô tả
Cho mảng N số nguyên với N là số chẵn. Có hai loại phép toán cho phép trên mảng.
- Tăng giá trị bất kỳ phần tử nào của mảng lên 1.
- Nếu hai phần tử liền kề trong mảng là hai số nguyên tố liên tiếp, xóa cả hai phần tử.
Nhiệm vụ là tìm số phép toán tối thiểu cần thiết để xóa tất cả phần tử của mảng.
Ví dụ
Nếu mảng là {10, 13} thì cần tối thiểu 2 phép toán
- Tăng phần tử 1 của mảng lên 1. Mảng mới trở thành {11, 13}
- Xóa phần tử 1 và 2 vì cả hai là số nguyên tố liên tiếp
Thuật toán
1. Để xóa số, phải biến đổi hai số thành hai số nguyên tố liên tiếp. 2. Giả sử a và b là số nguyên tố liên tiếp, dùng sàng Eratosthenes để tính trước số nguyên tố và tìm số nguyên tố p đầu tiên không lớn hơn a và số nguyên tố đầu tiên lớn hơn p dùng mảng. 3. Sau khi tính toán xong dùng quy hoạch động để giải bài toán.
Ví dụ mã C++
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int minimumPrefixReversals(int *a, int n) {
string start = "";
string destination = "", t, r;
for (int i = 0; i < n; i++) {
start += to_string(a[i]);
}
sort(a, a + n);
for (int i = 0; i < n; i++) {
destination += to_string(a[i]);
}
queue<pair<string, int> > qu;
pair<string, int> p;
qu.push(make_pair(start, 0));
if (start == destination) {
return 0;
}
while (!qu.empty()) {
p = qu.front();
t = p.first;
qu.pop();
for (int j = 2; j <= n; j++) {
r = t;
reverse(r.begin(), r.begin() + j);
if (r == destination) {
return p.second + 1;
}
qu.push(make_pair(r, p.second + 1));
}
}
}
int main() {
int a[] = {1, 2, 4, 3};
int n = sizeof(a) / sizeof(a[0]);
cout << "Số lần đảo ngược tối thiểu: " << minimumPrefixReversals(a, n) << endl;
return 0;
}
Khi biên dịch và thực thi chương trình trên. Nó tạo ra đầu ra sau:
Đầu ra
Số lần đảo ngược tối thiểu: 3