import java.io.*;
import java.util.*;

public class Main {
     /**
     * 主方法,程序的入口点
     *
     * @param args 命令行参数
     * @throws IOException 可能抛出IO异常
     */
    public static void main(String[] args) throws IOException {
        // 使用BufferedReader从标准输入读取数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 使用PrintWriter向标准输出写入数据
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        // 读取整数n,并去除可能的空白字符
        int n = Integer.parseInt(br.readLine().trim());

        // 初始化一个长度为n的数组,用于存储排列结果
        int[] track = new int[n];
        // 初始化一个长度为n+1的布尔数组,用于标记数字是否已被使用
        boolean[] used = new boolean[n + 1];

        // 调用回溯方法生成全排列
        backtrack(n, 0, track, used, out);
        // 刷新输出流,确保所有数据都被写出
        out.flush();
        // 关闭输出流
        out.close();
        // 关闭输入流
        br.close();


    }

    /**
     * 回溯法生成全排列
     *
     * @param n     排列的数字范围,1到n
     * @param depth 当前递归的深度,即已经确定的前几个数字的数量
     * @param track 当前排列的路径,存储已经确定的数字序列
     * @param used  标记数组,记录数字是否已经在当前排列中使用过
     * @param out   用于输出结果的打印流
     */
    private static void backtrack(int n, int depth, int[] track, boolean[] used, PrintWriter out) {
        // 如果当前深度等于n,说明已经生成了一个完整的排列
        if (depth == n) {
            // 输出当前排列
            for (int i = 0; i < n; i++) {
                // 如果是最后一个数字,直接输出,否则输出数字加空格
                out.print(track[i] + (i == n - 1 ? "" : " "));
            }
            // 换行,准备输出下一个排列
            out.println();
            // 返回上一层递归
            return;
        }

        // 遍历所有可能的数字
        for (int i = 1; i <= n; i++) {
            // 如果数字i还没有被使用过
            if (!used[i]) {
                // 标记数字i为已使用
                used[i] = true;
                // 将数字i放入当前深度的位置
                track[depth] = i;

                // 递归处理下一个位置
                backtrack(n, depth + 1, track, used, out);

                // 回溯,撤销选择,将数字i标记为未使用,以便尝试其他可能性
                used[i] = false;
            }
        }
    }
}