poj_2676

大致题意:

九宫格问题,也有人叫数独问题

把一个9行9列的网格,再细分为9个3*3的子网格,要求每行、每列、每个子网格内都只能使用一次1~9中的一个数字,即每行、每列、每个子网格内都不允许出现相同的数字。

 

0是待填位置,其他均为已填入的数字。

要求填完九宫格并输出(如果有多种结果,则只需输出其中一种)

如果给定的九宫格无法按要求填出来,则输出原来所输入的未填的九宫格

 

解题思路:

DFS试探,失败则回溯

 

用三个数组进行标记每行、每列、每个子网格已用的数字,用于剪枝

bool row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了

bool col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了

bool grid[10][10];   //grid[k][x] 标记在第k个3*3子格中数字z是否出现了

 

row 和 col的标记比较好处理,关键是找出grid子网格的序号与 行i列j的关系

即要知道第i行j列的数字是属于哪个子网格的

 

首先我们假设子网格的序号如下编排:


由于1<=i、j<=9,我们有: (其中“/”是C++中对整数的除法)


a= i/3 , b= j/3 ,根据九宫格的 行列 与 子网格 的 关系,我们有:


 

不难发现 3a+b=k

即 3*(i/3)+j/3=k

有了这个推导的关系式,问题的处理就变得非常简单了,直接DFS即可

(以上是神牛的思路,只要是grid数组适用的太精辟了)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#pragma warning(disable : 4996)
int n;
int map[10][10];
bool row[10][10];  //记录每行的数字是否可行
bool col[10][10];  //记录没列的数字是否可行
bool grid[10][10]; //记录每个九宫格的数字是否可行

void CreateMap()
{
	char str[10] = {0};
	for(int i = 0; i < 9; i++)
	{
		scanf("%s", str);
		for(int j = 0; j < 9; j++)
		{
			map[i][j] = str[j] - '0';
			if(map[i][j] != 0)
			{
				int num = map[i][j];
				int k = 3 * (i / 3) + j / 3;  // 这个公式很关键。这是求每个点对应的九宫格
				row[i][num] = true;
				col[j][num] = true;
				grid[k][num] = true;
			}
		}
	}
}

bool dfs(int i,int j)
{
	bool flag = false;
	if(i == 9) return true;
	if(map[i][j] != 0)
	{
		if(j == 8)
		{
			flag = dfs(i + 1, 0);
		}
		else
		{
			flag = dfs(i, j + 1);
		}
		if(flag)   //在这回溯,但不改变map的值,只起到一个传递的作用
			return true;
		else
			return false;
	}
	else
	{
		int k = 3 * (i / 3) + j / 3;
		for(int x = 1; x <= 9; x++)
		{
			if(!row[i][x] && !col[j][x] && !grid[k][x])
			{
				map[i][j] = x;
				row[i][x] = true;
				col[j][x] = true;
				grid[k][x] = true;
				if(j == 8)
				{
					flag = dfs(i + 1, 0);
				}
				else
				{
					flag = dfs(i, j + 1);
				}

				if(!flag)    //这也是一个回溯
				{
					map[i][j] = 0;
					row[i][x] = false;
					col[j][x] = false;
					grid[k][x] = false;
				}
				else
				{
					return true;
				}
			}//if
		}//for
	}
	return false;
}

void output()
{
	for(int i = 0; i < 9; i++)
	{
		for(int j = 0; j < 9; j++)
		{
			printf("%d", map[i][j]);
		}
		printf("\n");
	}
}

int main()
{
	freopen("in.txt","r",stdin);
	scanf("%d", &n);
	while(n--)
	{
		memset(row, false, sizeof(row));
		memset(col, false, sizeof(col));
		memset(grid, false, sizeof(grid));
		CreateMap();
		dfs(0, 0);
		output();
	}
	return 0;
}



转载于:https://my.oschina.net/N3verL4nd/blog/866787

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值