#include<bits/stdc++.h>
using namespace std;
vector<int>a;
vector<bool>vis;
vector<int>path;
void dfs(){
	if(path.size()==a.size()){
		for(int x:path)cout<<x<<" ";
	    cout<<"\n";
		return;
	}
	for(int i=0;i<a.size();i++){
		if(!vis[i]){
			vis[i]=true;
			path.push_back(a[i]);
			dfs();
			vis[i]=false;
			path.pop_back();
		}
	}
}
int main(){
	int n;
    cin>>n;
	for(int i=0;i<n;i++){
		a.push_back(i+1);
	}
    vis.resize(n,false);
	dfs();
	return 0;
}
//又写了一遍,对于递归与回溯有了更加深刻的理解:先从上往下执行完调用的dfs,再从下往上回溯。关键在于找到终止条件