Lab Assignment 08

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

Collaboration Policy

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.


Pre-Lab Requirement

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


Anagrams by Stack

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 ++--+- where each + designates a push and each - designates a pop.

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 ++-+-- or +-++--.

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
[
+++-+---
++-++---
+-+++---
]


Hints

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).


Tracing a Recursion

To better understand (and debug) recursive processes, it helps to generate a trace of a recursion. As a simple example, for the case of converting input "abc" to output "bac", the recursive processing based on our parameterization should proceed as follows:
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 solve(bca, bc, a, , +). From that state, you will find two separate brances of recursion develop, one for the action of pushing "b" onto the stack as the next move (hence moves="++"), or another independent branch if we were instead to pop "a" from the stack and place it on the output (hence moves="+-").

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;


Judge's Data

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.