这种数据结构真的是奇妙啊!!
推荐一篇博客 万仓一黍 的博客
Code:

1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N = 250501;
4 int n, m, cnt;//n行m列 cnt是总点数
5 int ans[N];
6 int row[N];//该点本身所在行
7 int col[N];//该点本身所在列
8 int l[N];//该点水平方向左侧
9 int r[N];//该点水平方向右侧
10 int up[N];//该点竖直方向的上一个点
11 int down[N];//该点竖直方向的下一个点
12 int s[N];//每一列点数
13 int h[N];//每一行表头
14 //这里水平,竖直方向上的列表都是循环的
15 void init(int m) {//初始化
16 for (int i = 0; i <= m; i++) {
17 r[i] = i + 1;
18 l[i] = i - 1;
19 up[i] = down[i] = i;
20 }
21 r[m] = 0;
22 l[0] = m;
23 memset(h, -1, sizeof h);
24 memset(s, 0, sizeof s);
25 cnt = m + 1;//我们在第0行插入了m个点作为辅助点
26 }
27 void insert(int R, int C) {//在R行C列插入点
28 s[C]++;
29 row[cnt] = R;
30 col[cnt] = C;
31 down[cnt] = C;//新节点的下一个点指向该列表头
32 up[cnt] = up[C];//新节点的上一个点是上一个节点
33 down[up[C]] = cnt;//上一个节点的下一个节点是该节点
34 up[C] = cnt;//上一个节点的下一个节点是新节点
35 if (h[R] == -1) {
36 h[R] = r[cnt] = l[cnt] = cnt;
37 } else {
38 r[cnt] = h[R];//新节点的右侧是表头
39 l[cnt] = l[h[R]];//新节点的左侧是表头的左侧即上一个节点
40 r[l[h[R]]] = cnt;//上一个节点的右侧是该新节点
41 l[h[R]] = cnt;//表头的左侧更新为新节点
42 }
43 cnt++;//节点数++
44 return;
45 }
46 void remove(int c) {//删除c列和c列所有点所在行
47 r[l[c]] = r[c];//c点左面的点的右面的点更新为c点右面的点
48 l[r[c]] = l[c];//c点右面的点的左面的点更新为c点左面的点
49 for (int i = up[c]; i != c; i = up[i]) {//枚举该列的点
50 for (int j = r[i]; j != i; j = r[j]) {//枚举该点所在行并将该行删除
51 down[up[j]] = down[j];//j点上一个点的下一个点是j点的下一个点
52 up[down[j]] = up[j];//j点下一个点的上一个点是j点的上一个点
53 s[col[j]]--;//该列点数--
54 }
55 }
56 }
57 void resume(int c) {//恢复
58 for (int i = down[c]; i != c; i = down[i]) {
59 for (int j = l[i]; j != i; j = l[j]) {
60 down[up[j]] = j;//该点的上一个点的下一个点是j自己
61 up[down[j]] = j;//该点的下一个点的上一个点是j自己
62 s[col[j]]++;//该列点数++
63 }
64 }
65 r[l[c]] = c;//c点左面的点的右面的点是c自己
66 l[r[c]] = c;//c点右面的点的左面的点是c自己
67 }
68 bool dance(int deep) {//Dance!
69 if (r[0] == 0) {//如果列表头没有元素,说明合法
70 for (int i = 0; i < deep; i++) {//将ans中的答案输出
71 printf("%d%c", ans[i], i == deep - 1 ? '\n' : ' ');
72 }
73 return true;
74 }
75 int c = r[0];
76 for (int i = r[0]; i != 0; i = r[i]) {
77 if (s[i] < s[c]) {//选择点数最少的列
78 c = i;
79 }
80 }
81 remove(c);//删除
82 for (int i = up[c]; i != c; i = up[i]) {//枚举该列所有点
83 ans[deep] = row[i];//将答案储存
84 for (int j = r[i]; j != i; j = r[j]) {//将该点所在行所有列删除
85 remove(col[j]);
86 }
87 if (dance(deep + 1)) {//判断是否合法
88 return true;
89 }
90 for (int j = l[i]; j != i; j = l[j]) {//回溯
91 resume(col[j]);
92 }
93 }
94 resume(c);//回溯
95 return false;
96 }
97 int main () {
98 scanf("%d%d", &n, &m);
99 init(m);
100 for (int i = 1; i <= n; i++) {
101 for (int j = 1; j <= m; j++) {
102 int x;
103 scanf("%d", &x);
104 if (x) {//是1就加点
105 insert(i, j);
106 }
107 }
108 }
109 if (!dance(0)) {
110 printf("No Solution!\n");
111 }
112 return 0;
113 }
