Open In App

CSES Solutions – Letter Pair Move Game

Last Updated : 19 May, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

There are 2n boxes in a line. Two adjacent boxes are empty, and all other boxes have a letter “A” or “B”. Both letters appear in exactly n-1 boxes.

Your task is to move the letters so that all letters “A” appear before any letter “B”. On each turn you can choose any two adjacent boxes that have a letter and move the letters to the two adjacent empty boxes, preserving their order.

It can be proven that either there is a solution that consists of at most 10n turns or there are no solutions.

Examples:

Input: N = 3, string = AB..BA
Output:
2
ABBA..
A..ABB
Explanation:

  • The first transformation swaps the two characters at indices 2 and 3 to create “ABBA..”.
  • The second transformation swaps the characters at indices 1 and 2, and at indices 4 and 5, resulting in “A..ABB”.

Input: N = 3, tstring = ABAB..
Output: -1
Explanation: It is not possible to transform the string to the desired form. This is because no sequence of swaps can produce a string with alternating ‘A’ and ‘B’ characters.

Approach: To solve the problem, follow the below idea:

To solve the problem efficiently, we first define a function solve(n) to create all possible string configurations for a given length n. Using a queue-based breadth-first search (BFS) approach, we start from the initial string configuration and iteratively explore all possible swaps. During the search, we store the predecessor of each string configuration to reconstruct the transformation path later. If the input length is less than 4, we extend the search by considering configurations of length n*2. For lengths of 4 or more, we check if the first two characters need swapping and perform the swap if necessary. Then, we conduct BFS for configurations of length 8. Subsequently, we iterate through the string, applying transformations for each segment of length 8. Finally, we output the number of transformations performed along with the transformed strings, providing a concise and effective solution strategy.

Step-by-step algorithm:

  • Define a function solve(n) to create all possible string configurations for a given length n.
  • Initialize an empty queue for BFS traversal and a map to store predecessors of each string configuration.
  • Enqueue the initial string configuration into the queue and set its predecessor to an empty string.
  • Perform BFS:
  • While the queue is not empty, dequeue a string configuration u.
  • For each possible swap operation, generate the new string configuration v.
  • If v is not already present in the predecessors map, enqueue v into the queue and set its predecessor to u.
  • Handle special cases:
  • If the length of the input string is less than 4, perform solve(n*2) to consider configurations of length n*2.
  • If the length is 4 or more:
  • Check if the first two characters need swapping.
  • If necessary, swap the first two characters and enqueue the resulting string into the queue with its predecessor set to the original string.

Below is the implementation of the algorithm:

C++
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define mem(a, b) memset(a, b, sizeof a)
#define For(i, l, r)                                       \
    for (int i = (l), i##e = (r); i < i##e; i++)
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define SZ(x) int((x).size())

using namespace std;

string s;
map<string, string> pre;
vector<string> ans;

// Function to explore all possible swaps
void bfs(int n)
{
    string q[448];
    int l = 0, r = 0;
    for (int k = 0; k <= (n < 8); k++) {
        for (int i = 0; i <= n - 2; i++) {
            string s
                = string(i, 'A') + string(n - 2 - i, 'B');
            s.insert(k, "..");
            q[r++] = s, pre[s] = "";
        }
    }
    while (l < r) {
        string u = q[l++];
        int k = u.find('.');
        for (int i = 0; i < n - 1; i++) {
            if (i <= k - 2 || i >= k + 2) {
                string v = u;
                swap(v[i], v[k]);
                swap(v[i + 1], v[k + 1]);
                if (!pre.count(v))
                    pre[v] = u, q[r++] = v;
            }
        }
    }
}

void solve(int l, int r)
{
    auto t = s.substr(l, r - l);
    while (pre[t] != "") {
        t = pre[t];
        ans.pb(s.substr(0, l) + t + s.substr(r));
    }
    s = s.substr(0, l) + t + s.substr(r);
}
int main()
{
    int n = 3;
    s = "AB..BA";
    // If the length is 2, then we only have empty
    // boxes. So, 0 moves are required
    if (n == 1) {
        cout << "0\n";
        return 0;
    }
    // If the length is less than 4, we extend the
    // search by considering configurations of length
    // n*2
    else if (n < 4) {
        bfs(n * 2);
        if (!pre.count(s))
            cout << "-1\n", exit(0);
        solve(0, n * 2);
    }
    else {
        int k = s.find('.');
        if (k > 1) {
            swap(s[k], s[k & 1]);
            swap(s[k + 1], s[(k & 1) + 1]);
            ans.pb(s);
        }
        bfs(8);
        solve(0, 8);
        int l = 0, r = n * 2;
        while (r - l > 8) {
            if (s[l + 2] == 'A' && s[l + 3] == 'A') {
                s[l] = s[l + 1] = 'A',
                s[l + 2] = s[l + 3] = '.';
                ans.pb(s), l += 2;
            }
            else {
                for (int i = l + 2; i < l + 8; i += 2) {
                    s[i - 2] = s[i], s[i - 1] = s[i + 1];
                    s[i] = s[i + 1] = '.';
                    ans.pb(s);
                }
                s[l + 6] = s[r - 2], s[l + 7] = s[r - 1];
                s[r - 2] = s[r - 1] = '.';
                ans.pb(s);
                s[r - 2] = s[l + 4], s[r - 1] = s[l + 5];
                s[l + 4] = s[l + 5] = '.';
                ans.pb(s), r -= 2;
            }
            solve(l, l + 8);
        }
    }
    cout << SZ(ans) << "\n";
    for (auto t : ans)
        cout << t << '\n';
}
Java
import java.util.*;

public class Main {
    static String s;
    static Map<String, String> pre = new HashMap<>();
    static List<String> ans = new ArrayList<>();

    // Function to explore all possible swaps
    static void bfs(int n)
    {
        String[] q = new String[448];
        int l = 0, r = 0;
        for (int k = 0; k <= (n < 8 ? 1 : 0); k++) {
            for (int i = 0; i <= n - 2; i++) {
                String s
                    = String.join(
                          "", Collections.nCopies(i, "A"))
                      + String.join(
                          "", Collections.nCopies(n - 2 - i,
                                                  "B"));
                s = new StringBuilder(s)
                        .insert(k, "..")
                        .toString();
                q[r++] = s;
                pre.put(s, "");
            }
        }
        while (l < r) {
            String u = q[l++];
            int k = u.indexOf('.');
            for (int i = 0; i < n - 1; i++) {
                if (i <= k - 2 || i >= k + 2) {
                    String v = u;
                    char temp = v.charAt(i);
                    v = v.substring(0, i) + v.charAt(k)
                        + v.substring(i + 1);
                    v = v.substring(0, k) + temp
                        + v.substring(k + 1);
                    temp = v.charAt(i + 1);
                    v = v.substring(0, i + 1)
                        + v.charAt(k + 1)
                        + v.substring(i + 2);
                    v = v.substring(0, k + 1) + temp
                        + v.substring(k + 2);
                    if (!pre.containsKey(v)) {
                        pre.put(v, u);
                        q[r++] = v;
                    }
                }
            }
        }
    }

    static void solve(int l, int r)
    {
        String t = s.substring(l, r);
        while (!pre.get(t).equals("")) {
            t = pre.get(t);
            ans.add(s.substring(0, l) + t + s.substring(r));
        }
        s = s.substring(0, l) + t + s.substring(r);
    }

    public static void main(String[] args)
    {
        int n = 3;
        s = "AB..BA";
        // If the length is 2, then we only have empty
        // boxes. So, 0 moves are required
        if (n == 1) {
            System.out.println("0");
            return;
        }
        // If the length is less than 4, we extend the
        // search by considering configurations of length
        // n*2
        else if (n < 4) {
            bfs(n * 2);
            if (!pre.containsKey(s)) {
                System.out.println("-1");
                System.exit(0);
            }
            solve(0, n * 2);
        }
        else {
            int k = s.indexOf('.');
            if (k > 1) {
                char temp = s.charAt(k);
                s = s.substring(0, k) + s.charAt(k & 1)
                    + s.substring(k + 1);
                s = s.substring(0, k & 1) + temp
                    + s.substring((k & 1) + 1);
                ans.add(s);
            }
            bfs(8);
            solve(0, 8);
            int l = 0, r = n * 2;
            while (r - l > 8) {
                if (s.charAt(l + 2) == 'A'
                    && s.charAt(l + 3) == 'A') {
                    s = s.substring(0, l) + "AA"
                        + s.substring(l + 2);
                    s = s.substring(0, l + 2) + ".."
                        + s.substring(l + 4);
                    ans.add(s);
                    l += 2;
                }
                else {
                    for (int i = l + 2; i < l + 8; i += 2) {
                        s = s.substring(0, i - 2)
                            + s.substring(i, i + 2)
                            + s.substring(i - 2, i)
                            + s.substring(i + 2);
                        ans.add(s);
                    }
                    s = s.substring(0, l + 6)
                        + s.substring(r - 2, r)
                        + s.substring(l + 8);
                    s = s.substring(0, r - 2) + ".."
                        + s.substring(r);
                    ans.add(s);
                    s = s.substring(0, r - 2)
                        + s.substring(l + 4, l + 6)
                        + s.substring(r);
                    s = s.substring(0, l + 4) + ".."
                        + s.substring(l + 6);
                    ans.add(s);
                    r -= 2;
                }
                solve(l, l + 8);
            }
        }
        System.out.println(ans.size());
        for (String t : ans)
            System.out.println(t);
    }
}
Python
from collections import deque

s = ""
pre = {}
ans = []


def bfs(n):
    global s, pre
    q = deque()
    for k in range(2):
        for i in range(n - 1):
            init_string = 'A' * i + 'B' * (n - 2 - i)
            config = init_string[:k] + '..' + init_string[k:]
            q.append(config)
            pre[config] = ""

    while q:
        u = q.popleft()
        k = u.find('..')

        for i in range(n - 1):
            if i <= k - 2 or i >= k + 2:
                v = list(u)
                temp = v[i]
                v[i] = v[k]
                v[k] = temp
                temp = v[i + 1]
                v[i + 1] = v[k + 1]
                v[k + 1] = temp
                v = ''.join(v)
                if v not in pre:
                    pre[v] = u
                    q.append(v)


def solve(l, r):
    global s, pre, ans
    t = s[l:r]
    while pre[t] != "":
        t = pre[t]
        ans.append(s[:l] + t + s[r:])
    s = s[:l] + t + s[r:]


def main():
    global s, pre, ans
    n = 3
    s = "AB..BA"

    if n == 1:
        print("0")
        return

    if n < 4:
        bfs(n * 2)
        if s not in pre:
            print("-1")
            return
        solve(0, n * 2)
    else:
        k = s.find('..')

        if k > 1:
            s = list(s)
            temp = s[k]
            s[k] = s[1]
            s[1] = temp
            temp = s[k + 1]
            s[k + 1] = s[2]
            s[2] = temp
            s = ''.join(s)
            ans.append(s)

        bfs(8)
        solve(0, 8)
        l, r = 0, n * 2

        while r - l > 8:
            if s[l + 2:l + 4] == 'AA':
                s = list(s)
                s[l] = s[l + 1] = 'A'
                s[l + 2] = s[l + 3] = '.'
                s = ''.join(s)
                ans.append(s)
                l += 2
            else:
                for i in range(l + 2, l + 8, 2):
                    s = list(s)
                    temp = s[i - 2]
                    s[i - 2] = s[i]
                    s[i] = temp
                    temp = s[i - 1]
                    s[i - 1] = s[i + 1]
                    s[i + 1] = temp
                    s = ''.join(s)
                    ans.append(s)

                s = list(s)
                temp = s[l + 6]
                s[l + 6] = s[r - 2]
                s[r - 2] = temp
                temp = s[l + 7]
                s[l + 7] = s[r - 1]
                s[r - 1] = temp
                ans.append(''.join(s))
                temp = s[l + 4]
                s[l + 4] = s[r - 2]
                s[r - 2] = temp
                temp = s[l + 5]
                s[l + 5] = s[r - 1]
                s[r - 1] = temp
                temp = s[l + 4]
                s[l + 4] = '.'
                s[l + 5] = '.'
                ans.append(''.join(s))
                r -= 2
            solve(l, l + 8)

    print(len(ans))
    for t in ans:
        print(t)


if __name__ == "__main__":
    main()
# this code is contributed by Aman.
JavaScript
let s;
let pre = new Map();
let ans = [];

// Function to explore all possible swaps
function bfs(n) {
    let q = [];
    let l = 0, r = 0;
    for (let k = 0; k <= (n < 8 ? 1 : 0); k++) {
        for (let i = 0; i <= n - 2; i++) {
            let str = "A".repeat(i) + "B".repeat(n - 2 - i);
            let s = str.slice(0, k) + ".." + str.slice(k);
            q.push(s);
            pre.set(s, "");
            r++;
        }
    }
    while (l < r) {
        let u = q[l++];
        let k = u.indexOf('.');
        for (let i = 0; i < n - 1; i++) {
            if (i <= k - 2 || i >= k + 2) {
                let v = u;
                let temp = v[i];
                v = v.substring(0, i) + v[k] + v.substring(i + 1);
                v = v.substring(0, k) + temp + v.substring(k + 1);
                temp = v[i + 1];
                v = v.substring(0, i + 1) + v[k + 1] + v.substring(i + 2);
                v = v.substring(0, k + 1) + temp + v.substring(k + 2);
                if (!pre.has(v)) {
                    pre.set(v, u);
                    q.push(v);
                    r++;
                }
            }
        }
    }
}

function solve(l, r) {
    let t = s.substring(l, r);
    while (pre.get(t) !== "") {
        t = pre.get(t);
        ans.push(s.substring(0, l) + t + s.substring(r));
    }
    s = s.substring(0, l) + t + s.substring(r);
}

function main() {
    let n = 3;
    s = "AB..BA";
    if (n == 1) {
        console.log("0");
        return;
    } else if (n < 4) {
        bfs(n * 2);
        if (!pre.has(s)) {
            console.log("-1");
            return;
        }
        solve(0, n * 2);
    } else {
        let k = s.indexOf('.');
        if (k > 1) {
            s = s.substring(0, k) + s[k & 1] + s.substring(k + 1);
            s = s.substring(0, k & 1) + s[k] + s.substring((k & 1) + 1);
            ans.push(s);
        }
        bfs(8);
        solve(0, 8);
        let l = 0, r = n * 2;
        while (r - l > 8) {
            if (s[l + 2] == 'A' && s[l + 3] == 'A') {
                s = s.substring(0, l) + "AA" + s.substring(l + 2);
                s = s.substring(0, l + 2) + ".." + s.substring(l + 4);
                ans.push(s);
                l += 2;
            } else {
                for (let i = l + 2; i < l + 8; i += 2) {
                    s = s.substring(0, i - 2) + s.substring(i, i + 2) 
                    + s.substring(i - 2, i) + s.substring(i + 2);
                    ans.push(s);
                }
                s = s.substring(0, l + 6) + s.substring(r - 2, r) + s.substring(l + 8);
                s = s.substring(0, r - 2) + ".." + s.substring(r);
                ans.push(s);
                s = s.substring(0, r - 2) + s.substring(l + 4, l + 6) + s.substring(r);
                s = s.substring(0, l + 4) + ".." + s.substring(l + 6);
                ans.push(s);
                r -= 2;
            }
            solve(l, l + 8);
        }
    }
    console.log(ans.length);
    ans.forEach(t => console.log(t));
}

main();

Output
2
ABBA..
A..ABB

Time complexity : O(448 + E) where E is the number of edges and depends on the length of the string.
Auxiliary Space: O(448)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads