POJ 3074 Sudoku(数据结构,DLX)
2014-06-27 14:52
417 查看
http://poj.org/problem?id=3074
数独求解,用一般的搜索要超时,从中间开始搜大概900+ms过。优雅的求解数独(精确覆盖问题)需要用到Dancing Links这个非常高大上的数据结构,《算法竞赛入门经典——训练指南》(刘汝佳)中有对DLX(Dancing Links X算法)的介绍。
DLX模板:
/article/2059866.html
DLX本身并不复杂,写起来可能有点小麻烦,但是求解这类问题最难的是构造出01矩阵 。
矩阵的行表示决策(我们要选择行),一共有9*9*9个决策:在r行c列的格子里填上数字v;
矩阵的列表示任务(目的是使得每列有且仅有1个1),一共有4种任务:
1.a行b列有数字
2.a行有数字b
3.a列有数字b
4.第a个方块要有数字b
所以一共有9*9*4列;
这样9*9的数独问题就转化成9*9*9行,9*9*4列的精确覆盖问题
Sudoku
In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,
Input The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”. Output For each test case, print a line representing the completed Sudoku puzzle. Sample Input .2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534. ......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3. end Sample Output 527389416819426735436751829375692184194538267268174593643217958951843672782965341 416837529982465371735129468571298643293746185864351297647913852359682714128574936 Source Stanford Local 2006 |
DLX模板:
/article/2059866.html
DLX本身并不复杂,写起来可能有点小麻烦,但是求解这类问题最难的是构造出01矩阵 。
矩阵的行表示决策(我们要选择行),一共有9*9*9个决策:在r行c列的格子里填上数字v;
矩阵的列表示任务(目的是使得每列有且仅有1个1),一共有4种任务:
1.a行b列有数字
2.a行有数字b
3.a列有数字b
4.第a个方块要有数字b
所以一共有9*9*4列;
这样9*9的数独问题就转化成9*9*9行,9*9*4列的精确覆盖问题
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<ctime> #include<cctype> #include<cmath> #include<string> #include<cstring> #include<stack> #include<queue> #include<list> #include<vector> #include<map> #include<set> #define sqr(x) ((x)*(x)) #define LL long long #define itn int #define INF 0x3f3f3f3f #define PI 3.1415926535897932384626 #define eps 1e-10 #define mm using namespace std; const int maxc=9*9*4+10; const int maxnode=9*9*9*4+10; const int maxr=9*9*9+10; struct DLX { int n,sz;//列数,结点数 int S[maxc];//各列结点数 int row[maxnode],col[maxnode];//各点行列编号 int L[maxnode],R[maxnode],U[maxnode],D[maxnode];//十字链表 int ansd,ans[maxr];//解 void init(int 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 =0;L[0]=n; sz=n+1; memset(S,0,sizeof S); } //插入决策行 _r 行号 columns 记录结点列号·[1,n] void add_row(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; } //删除一列结点 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 _resume(int _c) { for (int i=U[_c];i!=_c;i=U[i]) for (int j=L[i];j!=i;j=L[j]) { U[D[j]]=j;D[U[j]]=j;S[col[j]]++; } L[R[_c]]=_c; R[L[_c]]=_c; } bool dfs(int d) { if (R[0]==0) { ansd=d; //记录解的长度 return true; } //找最少结点的列删除 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])//反向恢复 _resume(col[j]); } _resume(_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; } }; int encode(int a,int b,int c) { return a*81+b*9+c+1; } void decode(int code,int &a,int &b,int &c) { code--; c=code%9; code/=9; b=code%9; code/=9; a=code; } char sudoku[100]; DLX solver; int main() { #ifndef ONLINE_JUDGE freopen("/home/fcbruce/文档/code/t","r",stdin); #endif // ONLINE_JUDGE while (scanf("%s",sudoku),strcmp(sudoku,"end")) { solver.init(9*9*4); for (int i=0;i<9;i++) { for (int j=0;j<9;j++) { for (int v=0;v<9;v++) { if (sudoku[i*9+j]=='.' || sudoku[i*9+j]=='1'+v) { vector<int> columns; columns.push_back(encode(0,i,j));//i行j列要有数字 columns.push_back(encode(1,i,v));//i行要有数字v columns.push_back(encode(2,j,v));//j列要有数字v columns.push_back(encode(3,(i/3)*3+j/3,v));//第(i/3)*3+j/3个方块要有数字v solver.add_row(encode(i,j,v),columns); } } } } vector<int> ans; solver.solve(ans); for (int i=0;i<ans.size();i++) { int r,c,v; decode(ans[i],r,c,v); sudoku[r*9+c]='1'+v; } puts(sudoku); } return 0; }
相关文章推荐
- POJ 3074 Sudoku 转化精确覆盖问题DLX
- POJ 3074 Sudoku DLX精确覆盖
- POJ 3074 Sudoku (DLX解经典数独)
- POJ 3074 Sudoku(DLX+精确覆盖)
- DLX(精确覆盖) POJ 3074 Sudoku
- poj 3074 Sudoku (精确覆盖,DLX,搜索)
- (模板题)poj 3074 Sudoku(DLX算法)
- 搜索(DLX): POJ 3074 3076 Sudoku
- (简单) POJ 3074 Sudoku, DLX+精确覆盖。
- POJ 3074 Sudoku (DLX)
- POJ 3074 Sudoku DLX
- POJ 3074 Sudoku [DLX] [SDLX]
- POJ 3074 Sudoku DLX精确覆盖
- POJ 3074 Sudoku DLX
- POJ 3074 Sudoku 解题报告(Dancing Link)
- POJ 3067 Sudoku DLX
- dancing links 算法学习小记 Poj 3074 Sudoku (数独)
- POJ 3067 Sudoku DLX
- Poj 3074: Sudoku
- POJ 3074 3076 Sudoku(Dancing Links)