zoukankan      html  css  js  c++  java
  • [poj3074]Sudoku(舞蹈链)

    题目链接:http://poj.org/problem?id=3074

    舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束
    1.每个位置有且只有一个数字
    2.每个位置的数字在一行只能出现一次
    3.每个位置的数字在一列只能出现一次
    4.每个位置的数字在一个宫格内只能出现一次
    然后针对每个位置可以建立舞蹈链了
    前81列,为1条件的约束
    82-162列,为2条件的约束
    163-243列,为3条件的约束
    244-324列,为4条件的约束
    则舞蹈链行数为确定的点数+未确定的点数*9,列数为324。
    如果i行j列为数k,对应行则在(i - 1) 9 + j列,(i - 1) 9 + k + 81列, (j - 1) 9 + k + 162列,(((i - 1) / 3) 3 + ((j + 2) / 3) - 1)* 9 + k + 243列建立。
    如果i行j列为未知数,则k为1-9,对于每个k都应该建立行列关系。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<vector>
      4 #include<cstring>
      5 #include<string>
      6 #include<algorithm>
      7 #include<set>
      8 #include<cstdlib>
      9 #include<map>
     10 #include<queue>
     11 #include<cmath>
     12 using namespace std;
     13 typedef long long ll;
     14 const int MN = 1010;
     15 const int MM = 500;
     16 const int MNN = MN * MM + 10;
     17 struct DLX {
     18 
     19     int n, m, size;//一共n行m列,size个节点
     20     int U[MNN], D[MNN], L[MNN], R[MNN], row[MNN], col[MNN];//第i个节点的上U下D左L右R,所在位置row行col列
     21     int H[MNN], S[MM];//H数组记录行选择指针,S数组记录覆盖个数
     22     int ansd, ans[MN];//res记录行个数,ans数组记录可行解
     23     void init(int x, int y) {//初始化空表
     24         n = x, m = y;
     25         for (int i = 0; i <= m; ++i) {//其中0节点作为head节点,其他作为列首节点
     26             U[i] = D[i] = i;
     27             L[i] = i - 1;
     28             R[i] = i + 1;
     29         }
     30         R[m] = 0; L[0] = m;
     31         size = m;
     32         memset(S, 0, sizeof(S));
     33         memset(H, -1, sizeof(H));
     34     }
     35     void Link(int r, int c) {
     36         size++; row[size] = r; col[size] = c; S[c]++;//节点数加一,设置s节点所处位置,以及S列覆盖个数加一
     37         D[size] = D[c]; U[D[c]] = size;//将s节点插入对应列中
     38         U[size] = c; D[c] = size;
     39         if (H[r] < 0)//如果该行没有元素,H[r]标记该行起始节点
     40             H[r] = L[size] = R[size] = size;
     41         else {//将该节点插入该行第一个节点后面
     42             R[size] = R[H[r]];
     43             L[R[H[r]]] = size;
     44             L[size] = H[r];
     45             R[H[r]] = size;
     46         }
     47     }
     48     //精确覆盖
     49     void remove(int c) {//删除c列
     50         L[R[c]] = L[c]; R[L[c]] = R[c];
     51         //删除该列上的元素对应的行
     52         for (int i = D[c]; i != c; i = D[i]) {//枚举该列元素
     53             for (int j = R[i]; j != i; j = R[j]) {//枚举列的某个元素所在行遍历
     54                 U[D[j]] = U[j];
     55                 D[U[j]] = D[j];
     56                 //将该列上的S数组减一
     57                 --S[col[j]];
     58             }
     59         }
     60     }
     61     void resume(int c) {//恢复c列
     62         for (int i = U[c]; i != c; i = U[i]) {//枚举该列元素
     63             for (int j = L[i]; j != i; j = L[j]) {
     64                 U[D[j]] = j; D[U[j]] = j;
     65                 ++S[col[j]];
     66             }
     67         }
     68         L[R[c]] = c; R[L[c]] = c;
     69     }
     70     bool dancing(int deep) {
     71         if (R[0] == 0) {//当矩阵为空时,说明找到一个可行解,算法终止
     72             ansd = deep;
     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 = D[c]; i != c; i = D[i]) {
     83             ans[deep] = row[i];//将行r放入当前解
     84             for (int j = R[i]; j != i; j = R[j])//行上节点对应的列上进行删除
     85                 remove(col[j]);
     86             //进入下一层
     87             if (dancing(deep + 1))return true;
     88             //对行上的节点对应的列进行恢复
     89             for (int j = L[i]; j != i; j = L[j])
     90                 resume(col[j]);
     91         }
     92         //恢复节点数最少列
     93         resume(c);
     94         return false;
     95     }
     96 };
     97 DLX dzl;
     98 int mp[15][15];
     99 int x[1010];
    100 int y[1010];
    101 int kk[1010];
    102 int main() {
    103     char s[100];
    104     while (cin >> s) {
    105         if (strcmp(s, "end") == 0)
    106             break;
    107         for (int i = 0; i < 81; i++) {
    108             int xx = i / 9;
    109             int yy = i % 9;
    110             if (s[i] == '.')
    111                 mp[xx + 1][yy + 1] = 0;
    112             else
    113                 mp[xx + 1][yy + 1] = s[i] - '0';
    114         }
    115         dzl.init(800, 324);
    116         int len = 1;
    117         for (int i = 1; i <= 9; i++) {
    118             for (int j = 1; j <= 9; j++) {
    119                 if (mp[i][j] == 0) {
    120                     for (int k = 1; k <= 9; k++) {
    121                         dzl.Link(len, (i - 1) * 9 + j);
    122                         dzl.Link(len, (i - 1) * 9 + k + 81);
    123                         dzl.Link(len, (j - 1) * 9 + k + 162);
    124                         dzl.Link(len, (((i - 1) / 3) * 3 + ((j + 2) / 3) - 1) * 9 + k + 243);
    125                         x[len] = i, y[len] = j, kk[len] = k;
    126                         len++;
    127                     }
    128                 }
    129                 else {
    130                     int k = mp[i][j];
    131                     dzl.Link(len, (i - 1) * 9 + j);
    132                     dzl.Link(len, (i - 1) * 9 + k + 81);
    133                     dzl.Link(len, (j - 1) * 9 + k + 162);
    134                     dzl.Link(len, (((i - 1) / 3) * 3 + ((j + 2) / 3) - 1) * 9 + k + 243);
    135                     x[len] = i, y[len] = j, kk[len] = k;
    136                     len++;
    137                 }
    138             }
    139         }
    140         dzl.dancing(0);
    141         for (int i = 0; i < dzl.ansd; i++) {
    142             int r = dzl.ans[i];
    143             mp[x[r]][y[r]] = kk[r];
    144         }
    145         for (int i = 1; i <= 9; i++) {
    146             for (int j = 1; j <= 9; j++) {
    147                 printf("%d", mp[i][j]);
    148             }
    149         }
    150         puts("");
    151     }
    152 }
  • 相关阅读:
    如何去掉修改Joomla、joomlart及其模版版权、标志、图标的方法
    如何joomla修改版权信息
    嫌我的键盘的backspace太小,就尝试了一下改键工具--keyTweak
    css3 -- 过渡与动画
    css3 -- 2D变换
    css3 -- 渐变
    css3 -- 颜色与不透明度
    css3 -- 背景图处理
    css3 -- 多列
    css3 -- 文本
  • 原文地址:https://www.cnblogs.com/sainsist/p/11147739.html
Copyright © 2011-2022 走看看