CSES Solutions – Letter Pair Move Game
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:
#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';
}
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);
}
}
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.
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)
Contact Us