IDA*
Before learning IDA*, please make sure you have completed the A* algorithm and iterative deepening search.
Introduction of IDA*¶
IDA* algorithm is actually the A* algorithm that uses iterative deepening technique. Compared with the A* algorithm, IDA* is more practical since it follows the depth-first rule:
- No need to check for duplicates. No need to sort.
-
Space requirement is reduced.
General framework (pseudocode):
Procedure IDA_STAR(StartState)
Begin
PathLimit := H(StartState) - 1;
Succes := False;
Repeat
inc(PathLimit);
StartState.g = 0;
Push(OpenStack, StartState);
Repeat
CurrentState := Pop(OpenStack);
If Solution(CurrentState) then
Success = True
Elseif PathLimit >= CurrentState.g + H(CurrentState) then
For each Child(CurrentState) do
Push(OpenStack, Child(CurrentState));
until Success or empty(OpenStack);
until Success or ResourceLimtsReached;
end;
Advantage¶
- The space overhead is small, and deep down is actually a depth-first search with limited depth. Also, it is well known that DFS consumes smaller space.
- Beneficial for deep pruning.
Disadvantage¶
Repetitive search: In the process of backtracking, each time the depth increases, the search must be done again from the beginning.
In fact, the difference between the previous search and the adjacent searches is negligible.
Sample problem¶
Egypt fraction
Problem description
In ancient Egypt, people use the sum of unit fractions (that is,
For a fraction
Input integers
Sample input:
495 499
Sample output:
Case 1: 495/499=1/2+1/5+1/6+1/8+1/3992+1/14970
Analysis
Theoretically this problem can be solved by the backtracking method, but the solution tree would be a "horror" - not only the depth has no obvious upper bound, but the choice of addends is theoretically unlimited. In other words, if BFS is used, even one layer cannot be expanded, because each layer is infinite.
The solution is to use iterative deepening search: enumerate the upper limit of depth
The maximum depth
Please note that the estimates here are all optimistic, because the word at least is used. To be more academically specific, suppose the upper limit of depth is
If an optimistic valuation function can be designed to predict at least how many layers of nodes need to be expanded to obtain a solution, the iterative deepening search becomes the IDA* algorithm.
Code
// Egypt fraction problem
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int a, b, maxd;
typedef long long LL;
LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); }
// return the minimum c which satisfies 1/c <= a/b
inline int get_first(LL a, LL b) { return b / a + 1; }
const int maxn = 100 + 5;
LL v[maxn], ans[maxn];
// if the current solution v is better than the current optimal solution ans, update ans
bool better(int d) {
for (int i = d; i >= 0; i--)
if (v[i] != ans[i]) {
return ans[i] == -1 || v[i] < ans[i];
}
return false;
}
// the current depth is d; the denominator cannot be less than `from`, and the sum of fractions is exactly aa/bb
bool dfs(int d, int from, LL aa, LL bb) {
if (d == maxd) {
if (bb % aa) return false; // aa/bb must be the Egypt fraction
v[d] = bb / aa;
if (better(d)) memcpy(ans, v, sizeof(LL) * (d + 1));
return true;
}
bool ok = false;
from = max(from, get_first(aa, bb)); // beginning of enumeration
for (int i = from;; i++) {
// pruning: if the remaining maxd+1-d fractions are all 1/i, and the sum still does not exceed aa/bb, there is no solution
if (bb * (maxd + 1 - d) <= i * aa) break;
v[d] = i;
// calculate aa/bb-1/i and set the result as a2/b2
LL b2 = bb * i;
LL a2 = aa * i - bb;
LL g = gcd(a2, b2); // reduce the fraction
if (dfs(d + 1, i + 1, a2 / g, b2 / g)) ok = true;
}
return ok;
}
int main() {
int kase = 0;
while (cin >> a >> b) {
int ok = 0;
for (maxd = 1; maxd <= 100; maxd++) {
memset(ans, -1, sizeof(ans));
if (dfs(0, get_first(a, b), a, b)) {
ok = 1;
break;
}
}
cout << "Case " << ++kase << ": ";
if (ok) {
cout << a << "/" << b << "=";
for (int i = 0; i < maxd; i++) cout << "1/" << ans[i] << "+";
cout << "1/" << ans[maxd] << "\n";
} else
cout << "No solution.\n";
}
return 0;
}
Practice problems¶
buildLast update and/or translate time of this article,Check the history
editFound smelly bugs? Translation outdated? Wanna contribute with us? Edit this Page on Github
peopleContributor of this article OI-wiki
translateTranslator of this article Visit the original article!
copyrightThe article is available under CC BY-SA 4.0 & SATA ; additional terms may apply.