POJ 3074 解题报告

来源:互联网 发布:js移除元素的属性值 编辑:程序博客网 时间:2024/06/07 04:30

这道题也是数独题。做完了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来看,提高的空间还是很大的。

thestoryofsnow3074Accepted212K750MSC++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][n]){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][n]){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][n] != 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][n] = 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 rowfor (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 columnfor (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 blockfor (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 sudokuif (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 valuesint valuescopy[81][10];for (int n = 1; n <= 9; ++n){if (values[mini][n]){// 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][n] = values[i][n];}}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][n] = 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][n] = 1;}}else{values[i][0] = 1;for (int n = 1; n <= 9; ++n){values[i][n] = 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;}



0 0