您的位置:首页 > 其它

Sudoku(九宫格问题)

2013-07-08 16:52 337 查看
Sudoku(POJ2676)是一种简单的数字游戏,一个9×9的正方形表格被分成9个3×3的小正方形表格,在表格的某些单元格中,已填有数字1至9中的一个。游戏的任务是,在表格每一个空白单元格里填入数字1至9中的一个,使得9×9正方形表格的每一行和每一列以及9个3×3小正方形表格中,数字1至9都出现且仅出现一次。

你的任务是,编程求出给定Sudoku游戏的一种填法。例如,图1(a)游戏的一个解如图1(b)所示。

1

3

5

9

2

1

9

4

7

4

3

5

2

6

6

5

7

8

3

4

4

1

9

2

5

8

8

4

1

7

(a)

1

4

3

6

2

8

5

7

9

5

7

2

1

3

9

4

6

8

9

8

6

7

5

4

2

3

1

3

9

1

5

4

2

7

8

6

4

6

8

9

1

7

3

5

2

7

2

5

8

6

3

9

1

4

2

3

7

4

8

1

6

9

5

6

1

9

2

7

5

8

4

3

8

5

4

3

9

6

1

2

7

(b)

思路:用深搜法,两种方法,后一种是对前一种的优化。

代码如下:

#include <iostream>
using namespace std;
int map[10][10];//九宫格
//row[i][x]  标记在第i行中数字x是否出现了  
//col[j][y]  标记在第j列中数字y是否出现了 
//box[k][z] 标记在第k个3*3子格中数字z是否出现了 
bool row[10][10],col[10][10],box[10][10];
bool DFS(int x,int y)
{
	if (x == 10)
		return true;
	bool flag = false;
	if (map[x][y])
	{
		if (y == 9)
			flag = DFS(x + 1,1);
		else
			flag = DFS(x,y + 1);
		if (flag)//回溯
			return true;
		else
			return false;
	}
	else
	{
		int k = 3 * ((x - 1) / 3) + (y - 1) / 3 + 1;
		for (int i = 1; i <= 9; i++)
			if (!row[x][i] && !col[y][i] && !box[k][i])
			{
				map[x][y] = i;
				row[x][i] = true;
				col[y][i] = true;
				box[k][i] = true;
				if (9 == y)
					flag = DFS(x + 1,1);
				else
					flag = DFS(x,y + 1);
				if (!flag)//回溯
				{
					map[x][y] = 0;
					row[x][i] = false;
					col[y][i] = false;
					box[k][i] = false;
				}
				else
					return true;
			}
	}
	return false;
}
int main()
{
	int T,i,j;
	cin>>T;
	while (T--)
	{
		memset(row,false,sizeof(row));
		memset(col,false,sizeof(col));
		memset(box,false,sizeof(box));
		for (i = 1; i <= 9; i++)
			for (j = 1; j <= 9; j++)
			{
				cin>>map[i][j];
				if (map[i][j])
				{
					int k = 3 * ((i - 1) / 3) + (j - 1) / 3 + 1;
					row[i][map[i][j]] = true;
					col[j][map[i][j]] = true;
					box[k][map[i][j]] = true;
				}
			}
		DFS(1,1);
		for (i = 1; i <= 9; i++)
		{
			for (j = 1; j <= 9; j++)
				cout<<map[i][j];
			cout<<endl;
		}
	}
	return 0;
}


我们可以对以上代码进行优化,不需要每一个位置都要遍历,只遍历未填充数字的位置,代码如下:

#include <cstdio>
#include <cstring>
int row[9][10],col[9][10],box[9][10];
int map[9][9],pos[81][2],p,n;//place记录哪些位置需要填写
int DFS(int x,int y)
{
	int i,j;
	if (p == n)
	{
		for (i = 0 ; i < 9; i++)
		{
			for (j = 0; j < 9;j++)
				printf("%d",map[i][j]);
			printf("\n");
		}
		return 1;
	}
	for (i = 1 ; i <= 9; i++)
		if (!row[x][i] && !col[y][i] && !box[x / 3 * 3 + y / 3][i])
		{
			map[x][y] = i;
			row[x][i] = col[y][i] = box[x / 3 * 3 + y / 3][i] = 1;
			p++;
			if (DFS(pos[p][0],pos[p][1]))
				return 1;
			p--;
			map[x][y] = 0;
			row[x][i] = col[y][i] = box[x / 3 * 3 + y / 3][i] = 0;
		}
	return 0;
}
int main()
{
	int i,j,T;
	scanf("%d",&T);
	while (T--)
	{
		p = 0;
		memset(row,0,sizeof(row));
		memset(col,0,sizeof(col));
		memset(box,0,sizeof(box));
		for (i = 0; i < 9; i++)
		{
			for (j = 0; j < 9; j++)
			{
				scanf("%d",&map[i][j]);
				if (map[i][j])
				{
					row[i][map[i][j]] = 1;
					col[j][map[i][j]] = 1;
					box[i / 3 * 3 + j / 3][map[i][j]] = 1;
				}
				else
				{
					pos[p][0] = i;
					pos[p][1] = j;
					p++;
				}
			}
		}
		n = p;
		p = 0;
		DFS(pos[0][0],pos[0][1]);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: