Tracking method solutions drinking problems
First introduce the theory of backtracking method:
Problems P, usually expressed as:
For known, a state space E = = {(x1, x2, ..., xn) | xi ∈ Si, I = 1, 2, .. , n}, given a constraint set D of the component in the n-group group, requiring all of all N tumes of all constraints to D in E. Where Si is the definition domain of component XI and | Si | Limited, i = 1, 2, ... n. We call e-group groups of all constraints that satisfy D D.
For the constraints of the niece group (x1, x2, ..., xn), it is generally divided into two categories, one is a significant constraint, which gives an explicit restriction constraint for the components in the n-group group, such as when I ≠ j XI ≠ xj; another category is hidden constraint, which gives implicit limits for components in the n-group group, such as: f (x1, x2, ..., xn) ≠ 0, where F is hidden function. However, implicit explicit is not absolute, both can be converted to each other.
The simple method of solving the problem P is the exhaustion method, that is, all N tumears in E, which detects whether it satisfies all constraints. All satisfied is the solution to the problem P; as long as there is an unmet, it is not the solution P 's solution. Obviously, if M (i) = | S (i 1) |, i = 0, 1, ... N-1, then the exhaustion method requires M = M (0) * m (1) * ... * m (n-1) N-tuples a non-leakage. It is conceivable that its calculation is very large.
We have found that for many issues, the given constraint D is complete, that is, the I tuple (x1, x2, ..., xi) satisfying only x1, x2, ..., all constraints of Xi The J (j
This discovery tells us that for constraint set D has a complete problem P, once it is detected that a J group (X1, X2, ..., XJ) violates X1, X2, ..., XJ, one constraint You can affirm that any N toll group (x1, x2, ..., xj, ..., xn) is prefixed in (x1, x2, ..., x1) (x1, x2, ..., xj, ..., and xn), it is not necessary to go Search them, detect them. Backtracking Method is a more efficient algorithm that is more efficient than the above nature of these issues.
The backtracking method first expresses the state space E of the N-tuple of the problem P to a highly N-position-right ordered tree T, and all the solutions to the problem P in E are all pending solutions to the problem P in T. Tree T is similar to the retrieval tree. It can be constructed such that elements in Si can be arranged to X (I, 1), X (I, 2), ..., X (I, M (I-1)), i = 1, 2, ... , n. From the root start, each of the Nodes of the i-level of T layer has M (i) son. This M (i) son to their common father, according to the order from left to right, respectively, X (i 1, 1), X (i 1, 2), ..., x (i 1, M (i)), i = 0, 1, 2, ..., n-1. According to this configuration, an N tone group (X1, X2, ..., XN) corresponds to a leaf junction point in t, and the root of the roots of the Type of this leaf junction. X1, x2, ..., XN is the right to it, and vice versa. Further, for any 0 ≤ i ≤ N-1, an a prefix I tone group (X1, X2, ..., xi) corresponds to one of T in T in any 0 ≤ i ≤ N-1, E. The non-impenette node, the roots of T to this way of this non-impeller, respectively, X1, X2, ..., Xi is the right of X1, X2, ..., Xi, and vice versa. In particular, any of the n metaps in E is an air prefixed (), corresponding to the root of T. Thus, a solution to the problem P in E is a solution of a leaf junction in T, requiring the N rights X1, X2, respectively, respectively, respectively, respective N rights X1, X2, respectively, respective N rights X1, X2, respectively, respective N rights X1, X2, respectively. ......, XN meets all constraints of constraint set d. Searching in t in t, a natural way is to gradually deepen from the roots, and the road gradually extends, ie sequentially sequentially satisfying the prefix (XL) of the termination condition, the prefix 2 (XL) , x2), prefix I tuple (x1, x2, ..., xi), ... until I = N is. Note that here, we will only meet the D X1, X2, ..., XI of X1, X1 (x1, x2, ..., xi), as a judgment (x1, x2, ..., xi) is a problem P The necessary conditions for the solution are only the conditional conditions when this essential condition is added. To distinguish, we call the accumulated discriminant conditions (such as condition i = n) as ending conditions.
In the backtracking method, the tree T introduced above is called the state space tree of the problem P; any of the nodes on the tree T are referred to as the state node of the problem P; any one of the trees t is called The problem P is a decimal node; the tree T satisfies all about the annotation of the constraint set D is called an answer status node of question P, referred to as an answer node or answer status, it corresponds to A solution of the problem P.
For example, 8 Queen issues is to determine an 8-tuple (x1, x2, .., x8), XI means that the queen of the Queen of the row, this problem is easy to apply the above search tree model; however, some problems The solution cannot be expressed as a n-group group, because this is unable to determine how much this N is, such as this drinking problem, the problem is a series of pouring wine, but can't determine how many steps do you need to do in advance; 8 Digital Problem (the game on the 9x9 checkered in Wencheng), that question is also the need to move how many steps need to move in advance. However, this does not affect the use of backtracking, as long as the problem is solved, it will definitely demonstrate a limited change in the solution. We can assume that the number of changes in the solution of the problem, so you can continue to use the above Search tree model. In fact, this search tree is not predefined, but is gradually generated during the search, so that the depth N of the tree does not affect the leaves node in the tree. But it is very important. If the problem does not have a limited solution, or the status of the problem is infinite, then you can search the leaf node along a road, it may never reach the leaf node, because the search tree will continue to expand However, the leaf junction may be existing, as long as you change a road, you can find it, just get the wrong way at the beginning, and this error is never terminated. To avoid this situation, we generally specify that the state space is limited, so even each state of the entire state space can be completed within a limited time, otherwise the backtracking method is likely to not apply. Each node of the search tree represents a state, the node i to generate node J must meet the constraints in the constraint set, and we can also refer to this constraint condition or "generate rules" (meaning from nodes) i Generates the rules of node J, which is an angle from the "generating system" theory to explain the backtracking method). Therefore, the essence of the backtracking is in a state space, from the starting state (the root of the search tree), a path to the target state (the leaf of the tree) (just like the maze, this is the view The angle to explain the backtracking method). In general, in order to prevent loop from the search, the node (status) that has already passed is recorded, and the node (status) that cannot be repeated in the same path, so as long as the status space is limited, the backchaunk is always It is possible to terminate.
============================================================================================================================================================================================================= ==============================================================================================================================================
Below we will solve this drinking problem according to the backtracking
(1) The state indicates that one state represents x = (x1, x2, x3, x4, x5, x6, x7); wherein X1 ~ x3 represents A, B, C three wine bottles. Wine, X4 ~ X7 represents a wine that has been Dr. A, B, C, D, respectively; (2) Constraint Condition 1. Everyone drinks can't exceed 4; 2. Wines accommodated in each bottle cannot exceed the capacity of the bottle; in order to facilitate the wine, the wine does not exceed C [K], the capacity of the i kind of wine bottle is C [i], then C [1] = C [2] = 8, C [3] = 3, C [4] = C [5] = C [6] = C [7] = 4; constraint conditions are 0 <= x [i] <= C [i ];
(3) Transfer rules (status generation rules) Transfer from a state X to another y has the following cases: 1. I bottle in the bottle into the J bottle and filled the J bottle: y [i] = x [i] - (C [J] -X [j]), y [j] = c [j], i J∈ [1, 3] 2. The wine in the bottle is pour in the J bottle and puts the i bottle empty: y [i] = 0, y [j] = x [j] x [i], i, j∈ [1, 3] 3 . A personal J drinks the wine in the i bottle: y [i] = 0; y [j] = x [j] x [i], i∈ [1, 3], j∈ [4, 7] of course The status y must meet the constraints in (2);
(4) Initial state a, b is filled with wine, and C is empty: X0 [1] = C [1], X0 [2] = C [2], X0 [3] = C [3] , X0 [4] = X0 [5] = X0 [6] = X0 [7] = 0;
(5) The wine in the target state is empty, everyone is full of wine: XN [1] = xn [2] = xn [3] = 0, XN [4] = C [4], XN [5] = C [5], XN [6] = C [6], XN [7] = C [7];
The following is given a universal backtracking code:
Void DFS_TRY (S) {if (Status S is the target status) {print result; exit; // If you require all solutions, you exit the function, if you only ask for an export, you exit the entire program} for from state s Each state T IF (T is not in the stack is not in the stack) according to the generated rule; DFS_TRY (T); state T pops up the stack;}}
The main program is:
The initial state S0 is pressed into the stack; DFS_TRY (S0);
However, for this problem, if the efficiency is very low, it is very low, it is almost unbearable. So I have to improve it. We noticed that each state is a 7-piece group, and according to constraint conditions, all the number of legitimate states is 8 * 8 * 3 * 4 * 4 * 4 * 4 = 49152, fully record all status records Come down, even if you exhaust all the status, you can endure. So in the DFS_TRY above, we are not looking for a search that has been searched in the stack, but in a status table, find a search that has been searched, if a status in the status table indicates that the status has been searched. There is no need to search again. For example, the search tree searching out of the simple backtracking method is as follows: A / / / / B C / / / / / / / / /
From A, searching A - B - D - ... then retracts to A, also searching A - C - D - ..., because D is not repeated on the search path, so I can't find it in the stack. The D node is repeatedly searched, so repeatedly searching D and its subtree; if you use a table to record, if each node is searched, you search for A - B - D - ... backtrained to A, search Go to A - C - D, this time the table finds that D has been searched, you can no longer search D and its sub-tree.
This search strategy with a form is called "Memo Law" is a modification of dynamic planning. For dynamic planning and memo, see: http: //algorithm.myrice.com/Alagorithm/technique/dynamic_programming /index.htm
Memorandum's pseudo code:
BOOL Memoire_TRY (S) {if (State S is the target state) {Record state S; Return True; // Here, it is assumed that only the output of the output is required to obtain each state T IF generated by the generated rule (state T) No search) {// Note that the change mark status T here is accessed; if (DFS_TRY (T)) {recording state S; return true;}}} return false;}}} Return false;
The main program is:
Initialization Setting All States in the Status Table Unacounted to S0; if (Memoire_TRY (S0)) prints the record;
This doesn't need to set your stack yourself, but you need to maintain a status access table.
Below is a program written in this kind of thinking, pay attention, not the best solution, but it is easy to modify the program to find the best solution.
#include
Const int CUP_COUNT = 3; // Wood Cup Number const state_count = 7; // State Variable Dimension TypeDef Int State [State_count]; // Recording State Type const state constr = {8, 8, 3, 4, 4, 4, 4}; // constraint conditions const state start = {8, 8, 0, 0, 0, 0, 0}; // initial state const state goal = {0, 0, 0, 4, 4, 4, 4}; // Target state const amount_state_count = 10 * 10 * 10 * 10 * 10 * 10 * 10; // Space status number const Max_step = 50; // Suppose up to 50 steps can be found Const State Key = {3, 5, 3, 3, 2, 0, 0};
BOOL Visited [MAX_STATE_COUNT]; // Used to tag access
State result [max_step]; // record result; int step_count = 0; // Decide the number of steps used in the target
/ / Calculation Status S Position INT POS (Const State & S) {INT P = 0 in Status Table; for (INT I = 0; I / / Decision State A, B is equal BOOL Equal (const state & a, const state & b) {for (int i = 0; i Void PrintState (const state & s) {for (int i = 0; i // Memo method Search Bool Memoire_Try (const state & s, int adjust) {if (Memcmp (S, Goal, SIZEOF (S)) == 0) {// If it is the target status step_count = step; memcpy (result [step- 1], S, SIZEOF (S)); // Record state s return true;} INT I, J; // First rule, the i = Cup_count; i Return false;} // end of memoire_try