Algorithm & Visualization
Think: If a tube has 111221, is pouring the top 1 the same operation as pouring all three 1s?
Yes! As long as they are consecutive and the same color, they can be poured at once.
void dedup(vector &t, char *s) {
t.clear();
for (int i = 0; i < n; i++) {
if (i == 0 || t[t.size()-1] != s[i]-'1')
t.push_back(s[i]-'1');
}
}
Top(A) == Top(B): Pour from the taller stack to the shorter one (merge to reduce).
Top(A) == Top(C) or Top(B) == Top(C): Pour matching top into C.
If Size(A)==1 & Size(B)==1 & tops diff colors:
$\to$ Pour C (if any) to matching tube.
$\to$ Done!
If A is empty (same for B):
1. If Size(B) == 1: Pour C to A, done.
2. Else: Pour B's top to A (split), continue loop.
State: Top(A)=2 != Top(B)=1. C empty.
Action: Move B(1) to C.
State: Top(A)=2 == Top(B)=2.
Action: A taller than B, pour A(2) to B (merge).
State: A, B both have 1 layer left & diff colors.
Action: Pour C(1) back to A.
Done! A is all 1s, B is all 2s.
// Strategy 1: Same top color, merge
if (!ts[0].empty() && !ts[1].empty() && ts[0].back() == ts[1].back()) {
// Greedy: Pour taller tube into shorter one to reduce layers
if (ts[0].size() > ts[1].size()) {
ts[0].pop_back();
ans.push_back({1, 2});
} else {
ts[1].pop_back();
ans.push_back({2, 1});
}
continue;
}
// Edge Case B: Move to empty tube
// If a tube is empty, and the other has >1 layer, or that layer doesn't belong
if (ts[0].empty() && ts[1].size() > 1 && ts[1].back() != beaker ||
ts[1].empty() && ts[0].size() > 1 && ts[0].back() != beaker) {
int i = ts[0].empty() ? 0 : 1; // Target is empty tube i
ts[i].push_back(ts[1-i].back());
ts[1-i].pop_back();
ans.push_back({(1-i)+1, i+1});
}
// Edge Case A: End check & Beaker refill
if (ts[0].size() <= 1 && ts[1].size() <= 1) {
if (beaker != -1) {
// Beaker not empty, pour back to matching tube
// If T0 is empty or matches beaker, pour to T0
int i = (ts[0].empty() || ts[0].back() == beaker) ? 0 : 1;
ans.push_back({3, i+1});
}
break; // Done
}
// Strategy 2/3: Borrow/Fill Beaker
int i;
if (beaker == -1) i = ts[0].size() > ts[1].size() ? 0 : 1; // Beaker empty, take from taller
else i = ts[0].back() == beaker ? 0 : 1; // Beaker not empty, take matching
beaker = ts[i].back();
ts[i].pop_back();
ans.push_back({i+1, 3});
#include <bits/stdc++.h>
using namespace std;
int t,n,p,m;
char s1[100005], s2[100005];
vector<int> ts[2];
using pi = pair<int,int>;
vector<pi> ans;
int beaker;
void dedup(vector<int> &t, char *s) {
t.clear();
for (int i = 0; i < n; i++) {
if (i == 0 || t[t.size()-1] != s[i]-'1')
t.push_back(s[i]-'1');
}
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d %d", &n, &p);
scanf("%s", s1);
scanf("%s", s2);
// dedup the colors
dedup(ts[0], s1);
dedup(ts[1], s2);
beaker = -1;
ans.clear();
while (1) {
// merge the same color to the lower tube
if (!ts[0].empty() && !ts[1].empty() && ts[0].back() == ts[1].back()) {
if (ts[0].size() > ts[1].size()) {
ts[0].pop_back();
ans.push_back({1, 2});
} else {
ts[1].pop_back();
ans.push_back({2, 1});
}
continue;
}
// move to an empty tube
if (ts[0].empty() && ts[1].size() > 1 && ts[1].back() != beaker ||
ts[1].empty() && ts[0].size() > 1 && ts[0].back() != beaker) {
int i = ts[0].empty() ? 0 : 1;
ts[i].push_back(ts[1-i].back());
ts[1-i].pop_back();
ans.push_back({(1-i)+1, i+1});
}
// done if both have <= 1, move beaker liquid back if necessary
if (ts[0].size() <= 1 && ts[1].size() <= 1) {
if (beaker != -1) {
int i = (ts[0].empty() || ts[0].back() == beaker) ? 0 : 1;
ans.push_back({3, i+1});
}
break;
}
// move liquid from tube to beaker
int i;
if (beaker == -1)
i = ts[0].size() > ts[1].size() ? 0 : 1;
else
i = ts[0].back() == beaker ? 0 : 1;
beaker = ts[i].back();
ts[i].pop_back();
ans.push_back({i+1, 3});
}
printf("%d\n", (int)ans.size());
if (p > 1) {
for (auto &a: ans)
printf("%d %d\n", a.first, a.second);
}
}
return 0;
}