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

应该算是深度优先搜索吧?看到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' 得到的时输入的数字,而储存的位置为相应的-1
					isvaild[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=3
				int 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表示可以填写1
			
			int 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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值