POJ 3074 Sudoku 转化精确覆盖问题DLX
来源:互联网 发布:pnp网络摄像机软件 编辑:程序博客网 时间:2024/05/22 04:25
题目:
http://poj.org/problem?id=3074
题意:
每次给出一行
思路:
大概我学跳舞链的初衷就是为了解数独问题?之前用dfs写过超时了,然后百度了一个思路很难想的dfs才给过,效率还是不怎么样,然后今天用跳舞链,真是快的飞起。
可以发现,数独问题有以下四个约束:
- 对于每一行,每个数字只能出现一次
- 对于每一列,每个数字只能出现一次
- 对于每一块,每个数字只能出现一次
- 对于每一个位置,都要有数字填入
将其转化为一个精确覆盖问题,用行表示状态,用列表示约束。对于数独矩阵中的每一个位置,如果当前填入了数字,肯定只有一种状态,若还没有填入数字,那么有
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int X = 100000 + 10, N = 800 + 10, M = 400 + 10, INF = 0x3f3f3f3f;struct DLX{ int U[X], D[X], L[X], R[X], row[X], col[X]; int H[N], S[M]; int head, sz, tot, n, m, ans[N]; void init(int _n, int _m) { n = _n, m = _m; for(int i = 0; i <= m; i++) L[i] = i-1, R[i] = i+1, U[i] = D[i] = i, S[i] = 0; head = 0, tot = 0, sz = m; L[head] = m, R[m] = head; for(int i = 1; i <= n; i++) H[i] = -1; } void link(int r, int c) { ++S[col[++sz]=c]; row[sz] = r; D[sz] = D[c], U[D[c]] = sz; U[sz] = c, D[c] = sz; if(H[r] < 0) H[r] = L[sz] = R[sz] = sz; else R[sz] = R[H[r]], L[R[H[r]]] = sz, L[sz] = H[r], R[H[r]] = sz; } void del(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]) D[U[j]] = D[j], U[D[j]] = U[j], --S[col[j]]; } void recover(int c) { for(int i = U[c]; i != c; i = U[i]) for(int j = L[i]; j != i; j = L[j]) D[U[j]] = U[D[j]] = j, ++S[col[j]]; R[L[c]] = L[R[c]] = c; } bool dance(int dep) { if(R[head] == head) { tot = dep-1; return true; } int c = R[head]; for(int i = R[head]; i != head; i = R[i]) if(S[i] < S[c]) c = i; del(c); for(int i = D[c]; i != c; i = D[i]) { ans[dep] = row[i]; for(int j = R[i]; j != i; j = R[j]) del(col[j]); if(dance(dep + 1)) return true; for(int j = L[i]; j != i; j = L[j]) recover(col[j]); } recover(c); return false; }}dlx;void calc(int x, int y, int k, int len){ int r = ((x-1) * len + (y-1)) * len + k; dlx.link(r, (x-1) * len + k); dlx.link(r, len*len + (y-1) * len + k); int base = sqrt(1.0 * len); int block = (x-1) / base * base + (y-1) / base + 1;//计算出所在块 dlx.link(r, len*len*2 + (block-1) * len + k); dlx.link(r, len*len*3 + (x-1) * len + y);}void print(int len){ sort(dlx.ans + 1, dlx.ans + 1 + dlx.tot); for(int i = 1; i <= len; i++) for(int j = 1; j <= len; j++) printf("%d", dlx.ans[(i-1)*len+j] - ((i-1)*len + (j-1)) * len); printf("\n");}int main(){ char str[N]; int len = 9; while(scanf("%s", str+1), str[1] != 'e') { dlx.init(len * len * len, len * len * 4); for(int i = 1; i <= len; i++) for(int j = 1; j <= len; j++) if(str[(i-1)*len+j] == '.') for(int k = 1; k <= len; k++) calc(i, j, k, len); else calc(i, j, str[(i-1)*len+j]-'0', len); dlx.dance(1); print(len); } return 0;}
阅读全文
0 0
- POJ 3074 Sudoku 转化精确覆盖问题DLX
- POJ 3076 Sudoku 精确覆盖问题DLX
- poj 3074 Sudoku (精确覆盖,DLX,搜索)
- DLX(精确覆盖) POJ 3074 Sudoku
- POJ 3074 Sudoku DLX精确覆盖
- POJ 3074 Sudoku(DLX+精确覆盖)
- POJ 3076 Sudoku DLX精确覆盖
- DLX精确覆盖 poj2676 Sudoku
- POJ 3074 DLX精确覆盖求解数独问题
- HDU 4069 Squiggly Sudoku DLX 精确覆盖
- DLX精确覆盖 hdu4069 Squiggly Sudoku
- POJ 3074 Sudoku DLX
- 【精确覆盖问题】DLX算法
- DLX(精确覆盖) 16*16数独 POJ 3076 Sudoku
- LA 2659 && poj 3076 && zoj 3122 Sudoku(精确覆盖 + DLX)
- POJ 3740 DLX 精确覆盖模板题
- poj 3740 DLX(精确覆盖)
- POJ-3740-Easy Finding【DLX精确覆盖】
- 每日MySQL之021:EXPLAIN输出中的Join Types
- hdu6103Kirinriki(尺取法)
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
- C++ 字符串转换
- 模拟 最长上升子串
- POJ 3074 Sudoku 转化精确覆盖问题DLX
- XlistView 加载头部ViewPager 网络请求数据 存入数据库
- 量化交易,未来互联网金融的发展趋势
- sleep,yield,join,notify,wait,notifyAll区别
- MAC上创建局域网git项目仓库
- hiho 1553区间统计 莫队算法+分块思想
- 【C++学习】通过输入数来确定一个数组的动态大小
- 骇客代码雨!终端一键下代码雨教程。黑客帝国代码流
- mysql 多表更新