/***********************************************
* auth: tapilyoca *
* date: 07/13/2025 at 15:50:36 *
* dots: https://github.com/tapilyoca/dotilyoca *
***********************************************/
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1e9+7;
template<typename T>
using vec = vector<T>;
using ll = int;
using vll = vec<ll>;
using vvll = vec<vll>;
using pll = pair<ll,ll>;
using str = string;
#define pb push_back
#define dbg(x) if(1) cerr << #x << ": " << x << endl;
/***********************************************/
struct ParkingSpot {
ll topCar, botCar;
ll sz;
ParkingSpot(ll x, ll y) {
if(x == 0) {
topCar = botCar = sz = 0;
}
else if(y == 0) {
topCar = x;
sz = 1;
botCar = 0;
} else {
topCar = y;
botCar = x;
sz = 2;
}
}
ParkingSpot() : topCar(0), botCar(0), sz(0) {}
void push_car(ll c) {
assert(sz < 2);
botCar = topCar;
topCar = c;
sz++;
}
ll pop_top() {
ll temp = topCar;
topCar = botCar;
botCar = 0;
sz--;
return temp;
}
void print() {
cerr << topCar << " " << botCar << endl;
}
};
vec<ParkingSpot> parking;
map<ll,set<ll>> topCarToSpot;
queue<ll> free_colors, almost_free_colors;
vec<pll> output;
queue<ll> empties;
void drive_car(ll from, ll to) {
// cerr << "Driving " << from << " to " << to << endl;
if(parking[from].sz == 0) {
cerr << "WHAT THE HELL ARE YOU DOING" << endl;
assert(0);
}
if(parking[to].sz == 2) {
cerr << "CANT PUSH CAR HERE, " << to << " FULL" << endl;
assert(0);
}
topCarToSpot[parking[from].topCar].erase(from);
topCarToSpot[parking[from].topCar].insert(to);
parking[to].push_car(parking[from].pop_top());
// update our sets
if(parking[from].sz == 0) {
empties.push(from);
} else {
ll ccar = parking[from].topCar;
topCarToSpot[ccar].insert(from);
if(topCarToSpot[ccar].size() == 2) {
if(parking[*topCarToSpot[ccar].begin()].sz + parking[*topCarToSpot[ccar].rbegin()].sz < 4) {
free_colors.push(ccar);
} else {
almost_free_colors.push(ccar);
}
}
}
output.pb({from,to});
}
void drive_car_2(ll from, ll to) {
// cerr << "Mriving " << from << " " << to << endl;
parking[to].push_car(parking[from].pop_top());
output.pb({from,to});
}
void bruh(queue<ll> q) {
while(!q.empty()) {
cerr << q.front() << " ";
q.pop();
}
}
void solve() {
ll n, m;
cin >> n >> m;
parking.resize(m);
for(int i = 0; i < m; i++) {
ll x, y;
cin >> x >> y;
parking[i] = {x,y};
}
for(int i = 0; i < m; i++) {
if(parking[i].sz == 0) {
empties.push(i);
continue;
}
ll car = parking[i].topCar;
if(car) topCarToSpot[car].insert(i);
if(topCarToSpot[car].size() == 2) {
// cerr << car << ": " << *topCarToSpot[car].begin() << " " << *topCarToSpot[car].rbegin() << endl;
// check if this can be a free move
if(parking[*topCarToSpot[car].begin()].sz + parking[*topCarToSpot[car].rbegin()].sz < 4) {
free_colors.push(car);
} else {
almost_free_colors.push(car);
}
}
}
// cerr << "Free colors: ";
// bruh(free_colors);
// cerr << "\nAlmost free colors: ";
// bruh(almost_free_colors);
// cerr << endl;
while(!free_colors.empty() or (!almost_free_colors.empty() and !empties.empty())) {
if(!free_colors.empty()) {
ll car = free_colors.front();
free_colors.pop();
if(parking[*topCarToSpot[car].begin()].sz == 2) {
drive_car(*topCarToSpot[car].begin(), *topCarToSpot[car].rbegin());
} else {
drive_car(*topCarToSpot[car].rbegin(), *topCarToSpot[car].begin());
}
}
if(!almost_free_colors.empty() and !empties.empty()) {
ll car = almost_free_colors.front();
almost_free_colors.pop();
ll empty_spot = empties.front();
empties.pop();
parking[empty_spot] = {car, car};
ll f1 = *topCarToSpot[car].begin(), f2 = *topCarToSpot[car].rbegin();
parking[f1].pop_top();
parking[f2].pop_top();
output.pb({f1, empty_spot});
output.pb({f2, empty_spot});
if(parking[f1].sz == 0) empties.push(f1);
else {
ll f1c = parking[f1].topCar;
topCarToSpot[f1c].insert(f1);
if(topCarToSpot[f1c].size() == 2) {
if(parking[*topCarToSpot[f1c].begin()].sz + parking[*topCarToSpot[f1c].rbegin()].sz < 4) {
free_colors.push(f1c);
} else {
almost_free_colors.push(f1c);
}
}
}
if(parking[f2].sz == 0) empties.push(f2);
else {
ll f2c = parking[f2].topCar;
topCarToSpot[f2c].insert(f2);
if(topCarToSpot[f2c].size() == 2) {
if(parking[*topCarToSpot[f2c].begin()].sz + parking[*topCarToSpot[f2c].rbegin()].sz < 4) {
free_colors.push(f2c);
} else {
almost_free_colors.push(f2c);
}
}
}
// drive_car(*topCarToSpot[car].begin(), empty_spot);
// drive_car(*topCarToSpot[car].rbegin(), empty_spot);
}
}
if(!almost_free_colors.empty() and empties.empty()) {
cout << -1 << endl;
return;
}
// cerr << "Ok done with that now doing cycles" << endl;
map<ll,ll> carToTopPosn;
for(int i = 0; i < m; i++) {
carToTopPosn[parking[i].topCar] = i;
}
for(int i = 0; i < m; i++) {
if(parking[i].topCar == parking[i].botCar or parking[i].topCar == 0) continue;
if(empties.empty()) {
cout << -1 << endl;
return;
}
// fix this cycle
ll curr = i;
// dbg(i);
ll emptySlot = empties.front();
empties.pop();
drive_car_2(i,emptySlot);
do {
ll former = curr;
curr = carToTopPosn[parking[curr].topCar];
// cerr << "f/c: " << former << " " << curr << endl;
if(curr == i) {
drive_car_2(former,emptySlot);
empties.push(curr);
break;
} else {
drive_car_2(curr,former);
}
} while(curr != i);
// cerr << "Done with " << i << " heres parking: " << endl;
// for(int i = 0; i < m; i++) {
// cerr << parking[i].botCar << " " << parking[i].topCar << endl;
// }
}
cout << output.size() << endl;
for(auto[x,y] : output) cout << x+1 << " " << y+1 << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int t = 1;
while(t--) {
solve();
}
return 0;
}
/*
0 1 2 3 4 X
1 2 3 4 0 X
0 1 3 3 4 0 0
1 2 2 4 5 5 0
1 0 3 3 4 0 0
1 2 2 4 5 5 0
1 0 0 3 4 0 0
1 2 2 4 5 5 3
1 0 0 3 4 0 0
1 2 2 4 5 5 3
*/
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |