template <int MXNODE = 5000> // 稀疏矩阵最大点数
struct DLX {
    int n, m, cur; // 行 列 新节点指针
    int h[MXNODE];  //每行的头指针
    int u[MXNODE], d[MXNODE], l[MXNODE], r[MXNODE]; //每个点的上下左右指针
    int row[MXNODE], col[MXNODE]; //每个点所在行,列
    int s[MXNODE]; //每列的节点数
    int ans[MXNODE]; //选了那些行

    DLX(int n, int m): n(n), m(m) {
        cur = 0;
        memset(h, 0, sizeof(u));
        memset(u, 0, sizeof(u));
        memset(d, 0, sizeof(d));
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        memset(row, 0, sizeof(row));
        memset(col, 0, sizeof(col));
        memset(s, 0, sizeof(s));
        memset(ans, 0, sizeof(ans));
        init();
    }

    void init(){ //初始化第0行的列表头
        for(int y=0; y<=m; y++){
            u[y] = d[y] = y;
            l[y] = y-1; r[y] = y+1;
        }
        l[0]=m; r[m]=0; cur=m+1; //下一个点的编号
    }
    //尾插法 要逐行逐列顺序插入
    void link(int x,int y){ //在x行y列插入点 
        row[cur]=x; col[cur]=y; s[y]++;
        // 列表头y,原先y <--> u[y],变为y <--> cur <--> u[y]
        u[cur]=u[y]; // cur --> u[y]
        d[u[y]]=cur; // cur <--> u[y]
        d[cur]=y; // y <-- cur <--> u[y]
        u[y]=cur; // y <--> cur <--> u[y]

        // 行表头h[x]
        if (h[x] == 0) {
            h[x] = r[cur] = l[cur] = cur;
        } else {
            // 原先 l[h[x]] <--> h[x],变为l[h[x]] <--> cur <--> h[x]
            l[cur]=l[h[x]]; // l[h[x]] <-- cur
            r[l[h[x]]]=cur; // l[h[x]] <--> cur
            r[cur]=h[x]; // l[h[x]] <--> cur --> h[x]
            l[h[x]]=cur; // l[h[x]] <--> cur <--> h[x]
        }
        cur++;
    }
    void remove(int y){ //删除y列与关联行
        /*
            a <--> b <--> c
            to
            a <-- b --> c
              <------->
        */
        r[l[y]]=r[y], l[r[y]]=l[y]; // 虚拟表头删除当前点
        for(int i=d[y]; i!=y; i=d[i])   //向下
            for(int j=r[i]; j!=i; j=r[j]) //向右
                u[d[j]]=u[j], d[u[j]]=d[j], s[col[j]]--;
    }
    void resume(int y){ //恢复y列与关联行
        r[l[y]]=y, l[r[y]]=y;  
        for(int i=u[y]; i!=y; i=u[i])   //向上
            for(int j=l[i]; j!=i; j=l[j]) //向左
                u[d[j]]=j, d[u[j]]=j, s[col[j]]++;
    }
    bool dance(int dep){
        if(r[0]==0){
            for (int i=0; i<dep; i++) {
                cout << ans[i] << " ";
            }
            cout << "\\n";
            return true;
        }

        int y=r[0]; //找到点最少的列
        for(int i=r[0];i;i=r[i]) if(s[i]<s[y]) y=i;
        remove(y);
        for(int i=d[y];i!=y;i=d[i]) {
            //在y列含1的行中选择一行作为答案,这一行存在1的列也需要关联删除才能保证精准覆盖
            ans[dep]=row[i]; 
            for(int j=r[i];j!=i;j=r[j]) remove(col[j]);
            if(dance(dep+1)) return true;
            for(int j=l[i];j!=i;j=l[j]) resume(col[j]);
        }
        resume(y); 
        return false;
    }
};
/*

use:
DLX dlx(n, m);

dlx.link(i,j);

dlx.dance(0);

*/