【Dancing Links舞蹈链】poj 3076 Sudoku

来源:互联网 发布:如何进入淘宝vip商场 编辑:程序博客网 时间:2024/04/25 18:42

Source : poj 3076 Sudoku

http://poj.org/problem?id=3076


Problem Description
A Sudoku grid is a 16x16 grid of cells grouped in sixteen 4x4 squares, where some cells are filled with letters from A to P (the first 16 capital letters of the English alphabet), as shown in figure 1a. The game is to fill all the empty grid cells with letters from A to P such that each letter from the grid occurs once only in the line, the column, and the 4x4 square it occupies. The initial content of the grid satisfies the constraints mentioned above and guarantees a unique solution.

这里写图片描述

Write a Sudoku playing program that reads data sets from a text file.
Input
Each data set encodes a grid and contains 16 strings on 16 consecutive lines as shown in figure 2. The i-th string stands for the i-th line of the grid, is 16 characters long, and starts from the first position of the line. String characters are from the set {A,B,…,P,-}, where – (minus) designates empty grid cells. The data sets are separated by single empty lines and terminate with an end of file.

Output
The program prints the solution of the input encoded grids in the same format and order as used for input.

题意

16×16的数独游戏,不过数字1~9变成A~P了!

示例

Sample Input

–A—-C—–O-I
-J–A-B-P-CGF-H-
–D–F-I-E—-P-
-G-EL-H—-M-J–
—-E—-C–G—
-I–K-GA-B—E-J
D-GP–J-F—-A–
-E—C-B–DP–O-
E–F-M–D–L-K-A
-C——–O-I-L-
H-P-C–F-A–B—
—G-OD—J—-H
K—J—-H-A-P-L
–B–P–E–K–A-
-H–B–K–FI-C–
–F—C–D–H-N-

Sample Output

FPAHMJECNLBDKOGI
OJMIANBDPKCGFLHE
LNDKGFOIJEAHMBPC
BGCELKHPOFIMAJDN
MFHBELPOACKJGNID
CILNKDGAHBMOPEFJ
DOGPIHJMFNLECAKB
JEKAFCNBGIDPLHOM
EBOFPMIJDGHLNKCA
NCJDHBAEKMOFIGLP
HMPLCGKFIAENBDJO
AKIGNODLBPJCEFMH
KDEMJIFNCHGAOPBL
GLBCDPMHEONKJIAF
PHNOBALKMJFIDCEG
IAFJOECGLDPBHMNK


思路

DLX算法在数独问题中的应用
精确覆盖问题之DLX算法

【图文解释】 http://www.cnblogs.com/grenet/p/3145800.html

【论文1】http://www.docin.com/p-387677023.html

【论文2】http://wenku.baidu.com/link?url=iNBiCQxuADYjU93J4qo6rUJQ21ZczH3fVqq6Peqp_2aAzWTEOfzTPuzh8eCtAoAXBaiE-sglg4BOfL6ultIItffmqHj0bHgPW-6qCXF7zyG

数独问题转换为精确覆盖问题(N*N*N行N*N*4列0-1矩阵),DLX算法+刘汝佳模板(参见论文2和大白书P406)

In addition : poj 3074、poj 2676、swjtu_OJ 2095题目都可以用DLX解决

这里写图片描述


参考代码 poj 3076

/*====================================*\|*     舞蹈链    DLX                  *|\*====================================*//*Author:Hacker_vision*/#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<vector>#include<map>#include<climits>#define clr(k,v) memset(k,v,sizeof(k))#define ll long long#define eps 1e-8using namespace  std;const int SLOT = 0;const int ROW = 1;const int COL = 2;const int SUB = 3;const int N = 16;const int M = 4;const int maxr = N*N*N + 10;//行数const int maxn = N*N*4 + 10;//列数const int maxnode = maxr*maxn + 10;//总节点数char g[20][20];struct DLX{  int n,sz;//列数,节点总数  int S[maxn];//各列节点数  int row[maxnode],col[maxnode];//各节点行列编号  int L[maxnode],R[maxnode],U[maxnode],D[maxnode];//十字链表,用数组写的  int ansd,ans[maxr];//解  void init(int n){ //n是列数   this->n = n;   //虚拟节点   for(int i = 0; i <= n; ++ i){     U[i] = i;D[i] = i;L[i] = i - 1;R[i] = i + 1;   }   R[n] = 0;L[0] = n;   sz = n + 1;   memset(S,0,sizeof(S));  }  void addRow(int r,vector<int>columns){   int first= sz;   for(int i = 0; i < columns.size(); ++ i){    int c = columns[i];    L[sz] = sz - 1;R[sz] = sz + 1;D[sz] = c;U[sz] = U[c];    D[U[c]] = sz;U[c] = sz;    row[sz] = r;col[sz] = c;    S[c]++;sz++;   }   R[sz - 1] = first;L[first] = sz - 1;  }  //顺着链表A,遍历除s外的其他元素 // #define FOR(i,A,s) for(int i = A[s]; i != s;i = A[i])  void remove(int c){    L[R[c]] = L[c];    R[L[c]] = R[c];    for(int i = D[c]; i != c;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 restore(int c){    for(int i = U[c]; i != c; i = U[i])      for(int j = L[i]; j != i; j = L[j]){       ++S[col[j]];U[D[j]] = j;D[U[j]] = j;      }      L[R[c]] = c;      R[L[c]] = c;  }  bool dfs(int d){    if(R[0] == 0){        ansd = d;        return true;    }    //找S的最小列    int c = R[0]; //第一个未删除的列    for(int i = R[0];i != 0; i = R[i]) if(S[i] < S[c]) c = i;    remove(c);    for(int i = D[c]; i != c;i = D[i]){        ans[d] = row[i];        for(int j = R[i]; j != i; j = R[j]) remove(col[j]);        if(dfs(d+1)) return true;        for(int j = L[i]; j != i; j = L[j]) restore(col[j]);    }    restore(c);    return false;  }  bool solve(vector<int>&v){    v.clear();    if(!dfs(0)) return false;    for(int i = 0; i < ansd; ++ i) v.push_back(ans[i]);    return true;  }};//行、列的统一编解码函数。从1开始编号int encode(int a,int b,int c){  return a*N*N + b*N + c + 1;}void decode(int code,int& a,int& b,int& c){  code--;  c = code%N; code/=N;  b = code%N; code/=N;  a = code;}DLX dlx;int main(){  #ifndef ONLINE_JUDGE  freopen("input.txt","r",stdin);  #endif // ONLINE_JUDGE  while(scanf("%s",g[0]) == 1){    for(int i = 1;i < 16;++ i) scanf("%s",g[i]);    dlx.init(N*N*4);//列数    for(int r = 0; r < N; ++ r)      for(int c = 0; c < N; ++ c)        for(int v = 0; v < N; ++ v)          if(g[r][c] == '-'||g[r][c] == 'A' + v){          vector<int>columns;          columns.push_back(encode(SLOT,r,c));//列数分四种情况          columns.push_back(encode(ROW,r,v));          columns.push_back(encode(COL,c,v));          columns.push_back(encode(SUB,(r/M)*M+c/M,v));          dlx.addRow(encode(r,c,v),columns);        }   vector<int>ans;   dlx.solve(ans);   for(int i = 0; i <ans.size(); ++ i){    int r,c,v;    decode(ans[i],r,c,v);    g[r][c] = 'A' + v;   }   for(int i = 0; i < N; ++ i)    printf("%s\n",g[i]);   puts("");//防PE  }  return 0;}
  • 加粗 Ctrl + B
  • 斜体 Ctrl + I
  • 引用 Ctrl + Q
  • 插入链接 Ctrl + L
  • 插入代码 Ctrl + K
  • 插入图片 Ctrl + G
  • 提升标题 Ctrl + H
  • 有序列表 Ctrl + O
  • 无序列表 Ctrl + U
  • 横线 Ctrl + R
  • 撤销 Ctrl + Z
  • 重做 Ctrl + Y
0 0
原创粉丝点击