zoukankan      html  css  js  c++  java
  • 舞蹈链

    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
  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/Sundial/p/11830580.html
Copyright © 2011-2022 走看看