#include<iostream>
#include<cstring>
#include<ctime>
#include<bitset>
#include<random>
#include<algorithm>
#include<vector>
using namespace std ;
namespace IO
{
namespace Read
{
#define isdigit(ch) (ch >= '0' && ch <= '9')
#define SIZE (1 << 16)
char buf[SIZE] , *_now = buf , *_end = buf ;
char getchar()
{
if(_now == _end)
{
_now = _end = buf ;
_end += fread(buf , 1 , SIZE , stdin) ;
if(_now == _end)
return EOF ;
}
return *(_now++) ;
}
template<typename T>
void read(T& w)
{
w = 0 ;
short f = 1 ;
char ch = getchar() ;
while(!isdigit(ch))
{
if(ch == '-')
f = -1 ;
ch = getchar() ;
}
while(isdigit(ch))
w = (w << 1) + (w << 3) + (ch ^ 48) , ch = getchar() ;
w *= f ;
}
#define sb(ch) (ch == ' ' || ch == '\n')
void read(char* s)
{
char ch = getchar() ;
while(sb(ch))
ch = getchar() ;
int len = 0 ;
while(!sb(ch))
s[len++] = ch , ch = getchar() ;
}
void read(string& s)
{
char ch = getchar() ;
while(sb(ch))
ch = getchar() ;
while(!sb(ch))
s.push_back(ch) , ch = getchar() ;
}
#undef sb
template<typename a , typename...T>
void read(a& s , T&...ss)
{
read(s) , read(ss...) ;
}
void read(double& w)
{
w = 0 ;
short f = 1 ;
char ch = getchar() ;
while(!isdigit(ch))
{
if(ch == '-')
f = -1 ;
ch = getchar() ;
}
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() ;
if(ch == '.')
{
ch = getchar() ;
int len = 0 ;
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() , ++len ;
while(len)
w /= 10 , --len ;
}
w *= f ;
}
void read(float& w)
{
w = 0 ;
short f = 1 ;
char ch = getchar() ;
while(!isdigit(ch))
{
if(ch == '-')
f = -1 ;
ch = getchar() ;
}
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() ;
if(ch == '.')
{
ch = getchar() ;
int len = 0 ;
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() , ++len ;
while(len)
w /= 10 , --len ;
}
w *= f ;
}
void read(long double& w)
{
w = 0 ;
short f = 1 ;
char ch = getchar() ;
while(!isdigit(ch))
{
if(ch == '-')
f = -1 ;
ch = getchar() ;
}
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() ;
if(ch == '.')
{
ch = getchar() ;
int len = 0 ;
while(isdigit(ch))
w = w * 10 + (ch ^ 48) , ch = getchar() , ++len ;
while(len)
w /= 10 , --len ;
}
w *= f ;
}
template<typename T>
void read(T* s , int sta , int len)
{
for(int i = 0 ; i < len ; ++i)
read(s[i + sta]) ;
}
class qistream
{
public:
template<typename T>
qistream& operator>>(T& a)
{
read(a) ;
return *this ;
}
} qcin ;
}
namespace Write
{
#define SIZE (1 << 16)
char buf[SIZE] , *p = buf ;
void flush()
{
fwrite(buf , 1 , p - buf , stdout) ;
p = buf ;
}
void putchar(char ch)
{
if(p == buf + SIZE)
flush() ;
*p = ch ;
++p ;
}
class Flush{public:~Flush(){flush() ;};}_;
template<typename T>
void write(T x)
{
char st[50] ;
int len = 0 ;
if(x < 0)
putchar('-') , x = -x ;
do
{
st[++len] = x % 10 + '0' ;
x /= 10 ;
} while(x) ;
while(len)
putchar(st[len--]) ;
}
void write(char c)
{
putchar(c) ;
}
void write(const char* s)
{
int siz = strlen(s) ;
for(int i = 0 ; i < siz ; ++i)
putchar(s[i]) ;
}
void write(string& s)
{
int siz = s.size() ;
for(int i = 0 ; i < siz ; ++i)
putchar(s[i]) ;
}
template<typename a , typename...T>
void write(a& s , T&...ss)
{
write(s) , write(ss...) ;
}
void write(double x , int len = 6)
{
if(x < 0)
write('-') , x = -x ;
__int128 sb = __int128(x) ;
x -= sb ;
int spar = 0 ;
for(int i = 0 ; i <= len ; ++i)
{
x *= 10 ;
if(int(x) == 0)
++spar ;
}
__int128 ssb = __int128(x) ;
if(ssb % 10 >= 5)
ssb += 10 ;
ssb /= 10 ;
write(sb) , write('.') ;
for(int i = 1 ; i <= spar ; ++i)
write('0') ;
write(ssb) ;
}
void write(float x , int len = 6)
{
if(x < 0)
write('-') , x = -x ;
__int128 sb = __int128(x) ;
x -= sb ;
int spar = 0 ;
for(int i = 0 ; i <= len ; ++i)
{
x *= 10 ;
if(int(x) == 0)
++spar ;
}
__int128 ssb = __int128(x) ;
if(ssb % 10 >= 5)
ssb += 10 ;
ssb /= 10 ;
write(sb) , write('.') ;
for(int i = 1 ; i <= spar ; ++i)
write('0') ;
write(ssb) ;
}
void write(long double x , int len = 6)
{
if(x < 0)
write('-') , x = -x ;
__int128 sb = __int128(x) ;
x -= sb ;
int spar = 0 ;
for(int i = 0 ; i <= len ; ++i)
{
x *= 10 ;
if(int(x) == 0)
++spar ;
}
__int128 ssb = __int128(x) ;
if(ssb % 10 >= 5)
ssb += 10 ;
ssb /= 10 ;
write(sb) , write('.') ;
for(int i = 1 ; i <= spar ; ++i)
write('0') ;
write(ssb) ;
}
template<typename T>
void write(T* s , int sta , int len , char c)
{
int en = sta + len - 1 ;
for(int i = sta ; i <= en ; ++i)
write(s[i]) , write(c) ;
}
template<typename T>
void write(T* s , int sta , int len , char* ss)
{
int en = sta + len - 1 ;
for(int i = sta ; i <= en ; ++i)
write(s[i]) , write(ss) ;
}
class qostream
{
public:
template<typename T>
qostream& operator<<(T x)
{
write(x) ;
return *this ;
}
} qcout ;
}
using namespace Read ;
using namespace Write ;
}
using namespace IO ;
vector<int> st[60] ;
vector<int> tmp[60] ;
int n = 0 , m = 0 ;
int op[405] = {} , len = 0 ;
bitset<60> use ;
int sp = 0 ;
struct opr
{
int fro , to ;
} ;
vector<opr> ope ;
int cou[60] = {} ;
inline void move(int x , int y)
{
st[y].push_back(st[x].back()) ;
st[x].pop_back() ;
ope.push_back((opr){x , y}) ;
}
inline void ti(int x , int color , int fu)
{
int cnt = 0 ;
for(unsigned i = 0 ; i < st[x].size() ; ++i)
if(st[x][i] == color)
++cnt ;
cou[x] = cnt ;
if(cnt == 0)
return ;
if(m - cnt >= cnt)
{
for(int i = 1 ; i <= cnt ; ++i)
move(fu , sp) ;
while(cnt)
{
int now = st[x].back() ;
if(now == color)
move(x , fu) , --cnt ;
else
move(x , sp) ;
}
int siz = st[x].size() ;
for(int i = 1 ; i <= m - cou[x] - siz ; ++i)
move(sp , x) ;
for(int i = 1 ; i <= cou[x] ; ++i)
move(fu , x) ;
while(!st[sp].empty())
move(sp , fu) ;
}
else
{
for(int i = 1 ; i <= m - cnt ; ++i)
move(fu , sp) ;
while(cnt)
{
int now = st[x].back() ;
if(now == color)
move(x , sp) , --cnt ;
else
move(x , fu) ;
}
int siz = st[x].size() ;
for(int i = 1 ; i <= m - cou[x] - siz ; ++i)
move(fu , x) ;
for(int i = 1 ; i <= cou[x] ; ++i)
move(sp , x) ;
while(!st[sp].empty())
move(sp , fu) ;
}
}
inline void clear(int x)
{
while(!st[x].empty())
{
int pu = 0 ;
for(int i = 1 ; i <= n + 1 ; ++i)
if(!use[i] && i != x && st[i].size() < m)
{
pu = i ;
break ;
}
while(st[pu].size() < m)
move(x , pu) ;
}
sp = x ;
}
int main()
{
srand(time(0)) ;
mt19937 myrand(rand()) ;
qcin>>n>>m ;
for(int i = 1 ; i <= n ; ++i)
{
for(int j = 1 ; j <= m ; ++j)
{
int a = 0 ;
qcin>>a ;
st[i].push_back(a) ;
tmp[i].push_back(a) ;
}
}
for(int i = 1 ; i <= n ; ++i)
op[++len] = i ;
while(1)
{
sp = n + 1 ;
for(int i = 1 ; i < n ; ++i)
{
memset(cou , 0 , sizeof cou) ;
int col = op[i] ;
for(int j = 1 ; j <= n + 1 ; ++j)
{
if(j == sp || use[j])
continue ;
for(int k = 1 ; k <= n + 1 ; ++k)
if(k != sp && k != j)
{
ti(j , col , k) ;
break ;
}
}
for(int j = 1 ; j <= n + 1 ; ++j)
{
if(j == sp || use[j] || cou[j] == 0)
continue ;
for(int k = 1 ; k <= cou[j] ; ++k)
move(j , sp) ;
}
use[sp] = true ;
clear(sp - 1) ;
}
if(ope.size() <= 820000)
break ;
shuffle(op + 1 , op + n + 1 , myrand) ;
ope.clear() ;
use.reset() ;
for(int i = 1 ; i <= n ; ++i)
{
st[i].clear() ;
for(unsigned j = 0 ; j < tmp[i].size() ; ++j)
st[i].push_back(tmp[i][j]) ;
}
st[n + 1].clear() ;
}
qcout<<ope.size()<<'\n' ;
for(unsigned i = 0 ; i < ope.size() ; ++i)
qcout<<ope[i].fro<<' '<<ope[i].to<<'\n' ;
return 0 ;
}