#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;

int main(){
    int n;
    cin>>n;
    vector<int> v[n*n+1];
    rep(i,2*n*n-2*n){
        int a,b;
        cin>>a>>b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    vector<vector<int>> ans(n,vector<int>(n)) ;
    vector<int> used(n*n+1);
    rep(i,n*n+1){
        if(v[i].size()==2){
            ans[0][0]=i;
            used[i]=1;
            break;
        }
    }
    rep(i,n-1){
        rep(j,i){
            for(auto to1 : v[ans[i-j][j]])for(auto to2 : v[ans[i-j-1][j+1]]){
                if(to1==to2&&!used[to1]){
                    ans[i-j][j+1]=to1;
                    used[to1]=1;
                    break;
                }
            }
        }
        for(auto to : v[ans[i][0]]){
            if(v[to].size()<=3&&!used[to]){
                ans[i+1][0]=to;
                used[to]=true;
                break;
            }
        }
        for(auto to : v[ans[0][i]]){
            if(v[to].size()<=3&&!used[to]){
                ans[0][i+1]=to;
                used[to]=true;
                break;
            }
        }
    }
    rep(i,n-1){
        REP(j,i,n-1){
            for(auto to1 : v[ans[n-1+i-j][j]])for(auto to2 : v[ans[n-1+i-j-1][j+1]]){
                if(to1==to2&&!used[to1]){
                    ans[n-1+i-j][j+1]=to1;
                    used[to1]=1;
                    break;
                }
            }
        }
    }
    rep(i,n){
        rep(j,n){
            cout<<ans[i][j];
            if(j<n-1)cout<<" ";
            else cout<<endl;
        }
    }
    return 0;
}
