POJ 3074 解题报告
2015-10-06 08:16
351 查看
这道题也是数独题。做完了2676后想把这道题也提交了凑数,结果发现TLE了。这道题比上道题题难些,简单暴力搜索无法通过了。看了discuss,提到一种新的算法,不想在学个冷僻的算法了。于是想到数独是AI中的基本题目,当时学到的基本策略在这里应该也是适用的。
于是看到了AI课本的作者Peter Norvig的post:Solving Every Sudoku Puzzle(http://norvig.com/sudoku.html),用的是CSP(constraint satisfaction problem)中的基本思路。效果特别好。
我这里用的是上述文章的简化版本。只考虑以下优化:
1.每次尝试(DFS)时,从有超过一种可能性,但是可能性种类最少的格子开始。比如格子1有123469共6种可能性,而格子3只有27两种可能性,那我们从格子3入手,快速失败的好处是我们避免了尝试后面的所有可能性。
2.我们在确定一个格子的数后,删除同行,同列,同block中的格子中的这个数。同时,如果一个格子在更新可能性后只剩下一种选择,那么我们也同时确定了这个格子的数(发散地消除其conflict所有格子的可能性)。
由于这两种优化已经能AC了,第三种可能非常有效的优化在这个没有使用:
3.如果对于一个数,比如3,在某行,或某列,或某block中只剩下一种可能的位置了,那么那个位置(格子)的数也确定了(3)。我们可以依此继续发散。从作者的post来看,提高的空间还是很大的。
于是看到了AI课本的作者Peter Norvig的post:Solving Every Sudoku Puzzle(http://norvig.com/sudoku.html),用的是CSP(constraint satisfaction problem)中的基本思路。效果特别好。
我这里用的是上述文章的简化版本。只考虑以下优化:
1.每次尝试(DFS)时,从有超过一种可能性,但是可能性种类最少的格子开始。比如格子1有123469共6种可能性,而格子3只有27两种可能性,那我们从格子3入手,快速失败的好处是我们避免了尝试后面的所有可能性。
2.我们在确定一个格子的数后,删除同行,同列,同block中的格子中的这个数。同时,如果一个格子在更新可能性后只剩下一种选择,那么我们也同时确定了这个格子的数(发散地消除其conflict所有格子的可能性)。
由于这两种优化已经能AC了,第三种可能非常有效的优化在这个没有使用:
3.如果对于一个数,比如3,在某行,或某列,或某block中只剩下一种可能的位置了,那么那个位置(格子)的数也确定了(3)。我们可以依此继续发散。从作者的post来看,提高的空间还是很大的。
thestoryofsnow | 3074 | Accepted | 212K | 750MS | C++ | 4724B |
/* ID: thestor1 LANG: C++ TASK: poj3074 */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <limits> #include <string> #include <vector> #include <list> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> using namespace std; int sudoku[81]; bool assign(int values[][10], int grid, int value); bool search(int values[][10]); void debugSudoku() { printf("[debug]sudoku:\n"); int i = 0; while (i < 81) { printf("%d ", sudoku[i]); i++; if (i % 9 == 0) { printf("\n"); } } } void printSudoku() { int i = 0; while (i < 81) { printf("%d", sudoku[i]); i++; } printf("\n"); } void debugValues(int values[][10]) { printf("[debug]values:\n"); for (int i = 0; i < 81; ++i) { printf("(%d, %d): [%d]", i / 9, i % 9, values[i][0]); for (int n = 1; n <= 9; ++n) { if (values[i] ) { printf("%d ", n); } } printf("\n"); } } void copyvalues2sudoku(int values[][10]) { for (int i = 0; i < 81; ++i) { for (int n = 1; n <= 9; ++n) { if (values[i] ) { sudoku[i] = n; break; } } } } bool remove(int values[][10], int grid, int value) { // printf("[debug]remove value %d from (%d, %d)\n", value, grid / 9, grid % 9); if (values[grid][value] == 1) { values[grid][value] = 0; values[grid][0]--; if (values[grid][0] < 1) { // printf("[debug]fail to remove as (%d, %d) will be empty without %d\n", grid / 9, grid % 9, value); return false; } else if (values[grid][0] == 1) { for (int n = 1; n <= 9; ++n) { if (values[grid] != 0) { // printf("[debug](%d, %d) has only one value %d\n", grid / 9, grid % 9, n); if (!assign(values, grid, n)) { return false; } break; } } } return true; } else { return true; } } bool assign(int values[][10], int grid, int value) { values[grid][0] = 1; for (int n = 1; n <= 9; ++n) { values[grid] = 0; } values[grid][value] = 1; int r = grid / 9, c = grid % 9; // printf("[debug]assign %d to (%d, %d)\n", value, r, c); // remove 'value' from grids in the same row for (int i = 0; i < 9; ++i) { int g = r * 9 + i; if (g != grid && !remove(values, g, value)) { return false; } } // remove 'value' from grids in the same column for (int i = 0; i < 9; ++i) { int g = i * 9 + c; if (g != grid && !remove(values, g, value)) { return false; } } // remove 'value' from grids in the same block for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { int g = (r / 3 * 3 + i) * 9 + (c / 3 * 3 + j); if (g != grid && !remove(values, g, value)) { return false; } } } return true; } bool search(int values[][10]) { bool allone = true; int mini = 0, minn = 9; for (int i = 0; i < 81; ++i) { if (values[i][0] != 1) { allone = false; if (values[i][0] < minn) { mini = i; minn = values[i][0]; } } } // if every grid has exactly one value, then we have solved the sudoku if (allone) { // printf("[debug]copy values to sudoku\n"); // debugValues(values); copyvalues2sudoku(values); return true; } // else we start trying from the grid has the minimum number of values int valuescopy[81][10]; for (int n = 1; n <= 9; ++n) { if (values[mini] ) { // printf("[debug]trying %d to (%d, %d)\n", n, mini / 9, mini % 9); for (int i = 0; i < 81; ++i) { for (int n = 0; n <= 9; ++n) { valuescopy[i] = values[i] ; } } if (assign(valuescopy, mini, n)) { if (search(valuescopy)) { return true; } } // we know that we cannot assign n to mini // so we remove 'n' from 'values[mini]' values[mini][0]--; values[mini] = false; } } return false; } int main() { char ch; int si = 0; int values[81][10]; while (scanf("%c", &ch) > 0 && ch != 'e') { // printf("[%c]\n", ch); if (ch == '.') { ch = '0'; } if (!('0' <= ch && ch <= '9')) { continue; } // printf("ri: %d, ci: %d, ch: %c\n", ri, ci, ch); sudoku[si] = ch - '0'; si++; if (si == 81) { // debugSudoku(); for (int i = 0; i < 81; ++i) { if (sudoku[i] == 0) { values[i][0] = 9; for (int n = 1; n <= 9; ++n) { values[i] = 1; } } else { values[i][0] = 1; for (int n = 1; n <= 9; ++n) { values[i] = 0; } values[i][sudoku[i]] = 1; } } for (int i = 0; i < 81; ++i) { if (sudoku[i] != 0) { assign(values, i, sudoku[i]); } } // debugValues(values); search(values); // debugSudoku(); printSudoku(); si = 0; } } return 0; }
相关文章推荐
- 一秒解决直接双击启动tomcat-startup.bat闪退
- 直连网线和交叉网线
- UI初级连载12-------------滑动视图
- this 的用法
- *LeetCode-Find the Duplicate Number
- 揭秘利用互联网营销的全国拍卖骗子公司 - (深圳拍卖公司)
- Matlab Error (Matrix dimensions must agree)
- 不要学习代码,要学会思考
- 持有对象:总结JAVA中的常用容器和迭代器,随机数 速查
- 数据结构实践项目——队列
- 经方败案群9月鼻炎专题第1场交流整理版
- 接口多适用类
- Servlet学习
- Linux网络配置和网络诊断命令介绍
- 今天继续码~python的文件访问~
- 关于显著性检测的思考
- Python BIF 汇总
- Spring 系列: Spring 框架简介
- LintCode "Find Peak Element II"
- Leetcode Strobogrammatic Number