• 舞蹈链


    LuoguP4929

    这种数据结构真的是奇妙啊!!

    推荐一篇博客 万仓一黍 的博客

    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 ? '
    ' : ' ');
     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!
    ");
    111     }
    112     return 0;
    113 }
    View Code
  • 相关阅读:
    Select与Epoll的区别
    C++ 多态详解及常见面试题
    Linux进程状态详解及状态转换
    C++ 设计模式之单例模式
    DS 图解归并排序
    TCP三次握手,四次挥手详解及常见面试题
    Linux 进程间通信(管道、共享内存、消息队列、信号量)
    # maven
    # select sort 选择排序
    # gitlab与git私钥公钥
  • 原文地址:https://www.cnblogs.com/Sundial/p/11830580.html
Copyright © 2020-2023  润新知