sicily--1317(深度优先搜索)

来源:互联网 发布:梦幻西游mac补丁 编辑:程序博客网 时间:2024/05/01 22:48

应该算是深度优先搜索吧?看到sicily 上说时间为10s ,直接来个暴力的! 但是 Time Limit Exceeded 了,先来暴力的代码:

#include<iostream>#include<cstring>#include<stdio.h>using namespace std;//表示九宫格的每个格子能填写的数字,  isvaild[0][0][0]=true 表示第一个格子能够填‘1’bool isvaild[9][9][9];//如果有解法,则存储第一种解法char ans[9][9];//题目char sudoku[9][9];//答案个数int anscont;//从输入中获得题目,并对相应的可访问性,格子的可填的数字访问范围做出设置void input(){for(int i = 0; i < 9; i++){for(int j = 0; j < 9; j++){//输入题目cin >> sudoku[i][j];//输入的是数字if(sudoku[i][j] != '_'){//(i, j)该格子设置为已访问//visited[i][j] = true;//每当输入了一个数字,会使得某些位置可填的数字范围发生改变//改变该数字所在的行、列for(int k = 0; k < 9; k++){//i 行的不能再填写此数字//因为sudoku[i][j] - '0' 得到的时输入的数字,而储存的位置为相应的-1isvaild[i][k][sudoku[i][j] - '0' - 1] = false;isvaild[k][j][sudoku[i][j] - '0' - 1] = false;}//改变该数字所在的小九宫格//i, j 分别表示所在小九宫格的起始行与列int row = i/3*3;//如2/3*3=0*3=0; 5/3*3=1*3=3int column = j/3*3;//m 移动行号, n 移动列号for(int m = 0; m < 3; m++){for(int n = 0; n < 3; n++){isvaild[row + m][column + n][sudoku[i][j] - '0' - 1] = false;}}}}}}//开始寻找解法,利用深度优先搜索//参数表示循环的次数,当循环到depth = 81时即搜索结束(表示当前填写的是哪个格子)//返回值为解法的个数int DFS(int depth){if(depth == 82)//已经填满了81个格子,搜索结束{if(anscont == 0)//目前还未找到解法,此为第一个{for(int p = 0; p < 9; p++){for(int q = 0; q < 9; q++){ ans[p][q]= sudoku[p][q];//获得第一个解法}}}return 1;//方法数+1}//搜索仍需继续//第 depth 个格子所在的行列int column = (depth - 1)%9;//例如第9个格子(0,8), (9-1)%9 = 8,表示在第8列int row = (depth - 1)/9; //例如第9个格子(0,8), (9 - 1)/9 = 0,表示在第0行//如果当前的格子已存有数字,则跳过,继续下一次的循环if(sudoku[row][column] != '_'){return DFS(depth + 1);//返回值为当确定下个格子时能有的解法个数}//如果到了这里,说明该格子上的不是数字//看这个格子能够填写什么数字//在此先“剪枝”,查看是否能够填数字,否则到此结束,说明此解法不存在int i;for(i = 0; i < 9; i++){if(isvaild[row][column][i] == true)//该格子能够填i+1{break;}}if(i == 9)//循环没有跳出{return 0; //解法数为0}//到此已经说明了,该格子是‘_’,也可以填写数字//开始遍历能填写的数字,并搜索下一个格子//anscont 记录当前位置能寻找到的路径数int anscont = 0;for(i = 0; i < 9; i++){if(isvaild[row][column][i] == true)//该格子能够填i+1{sudoku[row][column] = i + '1';//i = 0表示可以填写1int changeROW[81];int changeCOLUMN[81];int size = 0;//每当输入了一个数字,会使得某些位置可填的数字范围发生改变//改变该数字所在的行for(int k = 0; k < 9; k++){if(isvaild[row][k][i] == true){isvaild[row][k][i] = false;changeROW[size] = row;//记录改变了的行号与列号changeCOLUMN[size++] = k;}if(isvaild[k][column][i] == true){isvaild[k][column][i] = false;changeROW[size] = k;//记录改变了的行号与列号changeCOLUMN[size++] = column;}}//cout << size << endl;//改变该数字所在的小九宫格//m 移动行号, n 移动列号int Setrow = row/3*3;//所在小九宫图的起始行int Setcolumn = column/3*3;//所在小九宫图的起始列for(int m = 0; m < 3; m++){for(int n = 0; n < 3; n++){if(isvaild[Setrow + m][Setcolumn + n][i] == true){isvaild[Setrow + m][Setcolumn + n][i] = false;changeROW[size] = Setrow + m;changeCOLUMN[size++] = Setcolumn + n;}}}anscont = anscont + DFS(depth + 1);//当该格子定下后,开始访问下一个格子for(int g = 0; g<size; g++){isvaild[changeROW[g]][changeCOLUMN[g]][i] = true;}sudoku[row][column] = '_';}}return anscont;}int main(){int testNum;//题目个数/*cin >> testNum;*/scanf("%d",&testNum);int i = 0;while(testNum--){i++;//第几个题目;//九宫格的每个格子均可以填任意数字memset(isvaild, true, sizeof(isvaild));anscont = 0;//开始初始化题目input();//开始寻找解法,从第一个格子开始anscont = DFS(1);if(anscont == 1)//如果只有一个解法{printf("Puzzle %d solution is",i);//cout << "Puzzle " << i << " solution is" << endl;for(int m = 0; m < 9; m++){for(int n = 0; n < 9; n++){printf("%c",ans[m][n]);/*cout << ans[m][n];*/}//cout << endl;//输出完一行printf("\n");}}else{if(anscont == 0){printf("Puzzle %d has no solution\n",i);/*cout << "Puzzle " << i << " has no solution" << endl;*/}else//多解{printf("Puzzle %d has %d solutions\n",i, anscont);//cout << "Puzzle " << i << " has " << anscont << " solutions" << endl;}}}return 0;}


没办法,只能想办法优化一下了,选择可能性最小的格子开始,并在中途剪枝,时间:0.15s

还有就是,不能用memset() 函数来为一个非字符型数组赋初值是不允许的,这也让我纠结了好久!!

最坑爹的是最后竟然是表达有问题,又提交了好久!!!

#include<iostream>#include<cstring>#include<stdio.h>using namespace std;bool isvaild[9][9][9];char ans[9][9];char sudoku[9][9];int anscont;bool flag;//表示从第一个(count[0])格子到第81个格子能填的数字个数的数组//count[81]用来比较int count[82];void input(){for(int i = 0; i < 9; i++){for(int j = 0; j < 9; j++){cin >> sudoku[i][j];if(sudoku[i][j] != '_'){count[i*9 + j] = 0;//表示该格子已确定了数字,如sudoku[1][2]为第12个格子(count[11])for(int k = 0; k < 9; k++){if(isvaild[i][k][sudoku[i][j] - '0' - 1] == true)//为了不重复{isvaild[i][k][sudoku[i][j] - '0' - 1] = false;count[i*9 + k]--;}if(isvaild[k][j][sudoku[i][j] - '0' - 1] == true){isvaild[k][j][sudoku[i][j] - '0' - 1] = false;count[j + k*9]--;}}int startRow = i/3*3;int startColumn = j/3*3;for(int m = 0; m < 3; m++){for(int n = 0; n < 3; n++){if(isvaild[startRow + m][startColumn + n][sudoku[i][j] - '0' - 1] == true){isvaild[startRow + m][startColumn + n][sudoku[i][j] - '0' - 1] = false;count[(startRow + m)*9 + startColumn + n]--;}}}}}}}int DFS(){int minValIndex = 81;for(int i = 0; i < 81; i++)//找出可能性最小的格子{int ROW = i/9;int COLUMN = i%9;if(sudoku[ROW][COLUMN] != '_'){continue;//已填数字}//下面的都是还没填数字的if(count[i] == 0)//可以填数字,但是能填的个数为0,表明失败{return 0;}if(count[i] > 0 && count[i] < count[minValIndex])//非0表明还未确定数字{minValIndex = i;}}if(minValIndex == 81)//所有的格子均已确定了数字{if(flag == true)//第一个{flag = false;memcpy(ans, sudoku,sizeof(sudoku));}return 1;}int Anscont = 0;//确定当前位置后的解法数//该格子仍未确定数字,从可能的数字开始循环int row = minValIndex / 9;//如sudoku[1][2] 即 count[11] ,row = 11/9 = 1; column = 11%9 = 2;int column = minValIndex % 9;for(int i = 0; i < 9; i++){if(isvaild[row][column][i])//该格子能填i + 1{int changeCount[81];for(int j = 0; j < 81; j++){changeCount[j] = count[j];}sudoku[row][column] = i + '1';//填充数字isvaild[row][column][i] = false;count[row*9 + column] = 0;//已确定数字//记录哪些位置发生了改变,后面要恢复int changeRow[81];int changeColumn[81];int size = 0;//行列for(int j = 0; j < 9; j++){if(isvaild[row][j][i] == true){isvaild[row][j][i] = false;changeRow[size] = row;changeColumn[size++] = j;count[row*9 + j]--;//所在行}if(isvaild[j][column][i] == true){isvaild[j][column][i] = false;changeRow[size] = j;changeColumn[size++] = column;count[column + j*9]--;//所在列}}//小九宫图int startRow = row / 3 * 3;int startColumn = column / 3 * 3;for(int j = 0; j < 3; j++){for(int k = 0; k < 3; k++){if(isvaild[startRow + j][startColumn + k][i] == true){isvaild[startRow + j][startColumn + k][i] = false;changeRow[size] = startRow + j;changeColumn[size++] = startColumn + k;count[(startRow + j)*9 + startColumn + k]--;//所在九宫图}}}Anscont = Anscont + DFS();//搜索下个位置//恢复sudoku[row][column] = '_';isvaild[row][column][i] = true;for(int j = 0; j < size; j++){isvaild[changeRow[j]][changeColumn[j]][i] = true;}for(int j = 0; j < 81; j++){count[j] = changeCount[j];}}}return Anscont;}int main(){int testNum;scanf("%d",&testNum);for(int i = 1; i <= testNum; i++){memset(isvaild, true, sizeof(isvaild));//用memset对非字符型数组赋初值是不可取的//memset(count,9,81*sizeof(int));//每个格子初始化,能填9个数字,0表示已经确定了数字for(int j = 0; j < 81; j++){count[j] = 9;}count[81] = 100;anscont = 0;input();flag = true;anscont = DFS();if(anscont == 1)//如果只有一个解法{printf("Puzzle %d solution is\n",i);for(int m = 0; m < 9; m++){for(int n = 0; n < 9; n++){printf("%c",ans[m][n]);}printf("\n");}}else{if(anscont == 0){printf("Puzzle %d has no solution\n",i);}else//多解{printf("Puzzle %d has %d solutions\n",i, anscont);}}if(i != testNum)printf("\n");}return 0;}


原创粉丝点击