Topic: | Anagrams by Stack |
Source Code: | anagrams.cpp |
Live Archive Ref#: | variant of 2301 |
Pre-lab Due: |
Tuesday, March 20, by 9am (via email) |
Submission Deadline: | Friday, March 23, 11:59pm (via git) |
Techniques: |
Recursion |
The pre-lab requirement must be completed and submitted individually.
The remainder of the lab activity should be completed working in pairs. One person should submit the result, making sure that both partners' names are clearly identified in that submission.
Please make sure you adhere to the policies on academic integrity in this regard.
Read the complete problem description and then determine what the expected output should be if given the following input:
Prelab input: | Prelab output: |
3 long nice eric rice mada adam |
Consider the use of a stack for reordering a set of objects from one permutation (e.g., abc) to another (e.g., bac) using the following rules. The characters are given with an initial order, and there is an intermediate stack that is initially empty. At each step, you may either take the next character from the initial order (if any) and push it onto the stack, or you may pop an item from the stack (if any), and place it as the next character in the output string.
As an example, if you start with the sequence abc
you can achieve the result bac by
pushing a, pushing b,
popping b,
popping a,
pushing c, and finally popping c.
We can describe this sequence of maneuvers as
More generally, some inputs may not have any valid conversions while
others may have more than one valid sequence.
For example, it is impossible to go from abc to cab,
intuitively because the only way to get c as the first output
character would be to do three pushes followed by a pop; yet at that
time, b is above a on the stack and must be
retrieved next.
Yet there are two ways to go from aab to aba, either
as
You are to develop a program that computes all possible sequences for converting one string to another using such rules.
Input: The first line will be a value 1 ≤ n ≤ 100 denoting the number of pairs to be considered. Following that will be n lines, each containing two strings. The first string designates the starting sequence and the second the goal configuration. The goal string will always be the same length as the starting string, and strings will have length at most 10.
Output: For each case, an initial line should announce the initial and goal strings, formatted as demonstrated below. Following that should be a line with the character [, followed by zero or more lines detailing the solutions, followed by a final line with the character ]. When there are multipel solutions, they should be presented in lexicographically sorted order, with the character + ordered before -.
Example input: | Example output: |
4 abc bac abc cab aab aba eeep epee |
Output for abc bac [ ++--+- ] Output for abc cab [ ] Output for aab aba [ ++-+-- +-++-- ] Output for eeep epee [ +++-+--- ++-++--- +-+++--- ] |
Use recursion to explore possible solutions to the problem. At any intermediate stage, there are two possible continuations (if legal). Try them both. We used the following signature:
/** Outputs, in sorted order, all solutions derivable from the given configuration */ void solve(string goal, // the goal string string I, // unused portion of "initial" string string S, // current stack sequence string O, // (partial) output string string moves // '++-+-' style trace of moves thus far ) {
We have intentionally chosen to use strings because they are conveninent to duplicate and manipulate ( C++ string documentation). We have also intentionally tagged them all as const in the signature so that you do not change their state within a single recursive call (but you may create different strings when invoking a further recursion).
solve(bca, abc, , , ) solve(bca, bc, a, , +) solve(bca, c, ab, , ++) solve(bca, , abc, , +++) solve(bca, , ab, c, +++-) solve(bca, , a, cb, +++--) solve(bca, , , cba, +++---) solve(bca, c, a, b, ++-) solve(bca, , ac, b, ++-+) solve(bca, , a, bc, ++-+-) solve(bca, , , bca, ++-+--) solve(bca, c, , ba, ++--) solve(bca, , c, ba, ++--+) solve(bca, , , bac, ++--+-) solve(bca, bc, , a, +-) solve(bca, c, b, a, +-+) solve(bca, , bc, a, +-++) solve(bca, , b, ac, +-++-) solve(bca, , , acb, +-++--) solve(bca, c, , ab, +-+-) solve(bca, , c, ab, +-+-+) solve(bca, , , abc, +-+-+-)
For example, the initial call spawned another recursion based on
pushing "a" from the input onto the stack, thus
If you would like to produce this style of trace for your own program, you may add the following debugging command just within the body of your solve function:
cout << string(3*moves.size(),' ') << "solve(" << goal << ", " << I << ", " << S << ", " << O << ", " << moves << ")" << endl;
You can run the automated judge's tests on turing to test the correctness of your program (although you must still formally submit the source code via the course website). If you are working on your own machine (or if you just want to examine the judge's inputs and expected outputs), we provide them here.