POJ-2676 Sudoku(数独)解题报告


搜索依旧写的稀烂。。

题目概述

链接:https://vjudge.net/problem/POJ-2676
大概就是数独吧。。横、数、小九宫格内不重复。

思路分析

这种题主要的手法还是搜索、暴力枚举。这道题主要的难点是以什么为单位开始搜(其实也不难)以及怎么设置vis剪枝。
在这里,我选择了以搜索二叉树构建的map来记录vis(毕竟map查找起来较容易)。将9个小九宫格、每行、每列各构建一个map来记录,所以需要map数组。然后,按照从左到右,从上到下的顺序,以格子为单位开始搜索。每次遍历1到9,检查是否符合条件,遇到不行就回溯。大概就是这样了。。

完整代码

#include <iostream>
#include <map>
#include <cstring>
#include <cstdio>
#include <ctime>
using namespace std;
char floor[10][10]={0};
char floor_b[10][10]={0};
map<char,int> hang[10];
map<char,int> lie[10];
map<char,int> ge[10];
int flag=0;
inline int cnt_ge(int x,int y)//坐标->格子
{
	if(x<3)
	{
		if(y<3) return 0;
		else if(y<6) return 1;
		else if(y<9) return 2;
	}
	else if(x<6)
	{
		if(y<3) return 3;
		else if(y<6) return 4;
		else if(y<9) return 5;
	}
	else if(x<9)
	{
		if(y<3) return 6;
		else if(y<6) return 7;
		else if(y<9) return 8;
	}
}
inline bool judge(int x,int y,int i)
{
	if(hang[x][i+'0']==0&&lie[y][i+'0']==0&&ge[cnt_ge(x,y)][i+'0']==0) return 1;
	else return 0;
}
void dfs(int x,int y)
{
	if(x==0&&y==9&&flag==0)
	{
		flag=1;
		for(int i=0;i<9;i++)
		{
			for(int j=0;j<9;j++)
			{
				if(floor[i][j]=='0')
				{
					printf("%c",floor_b[i][j]);
				}
				else printf("%c",floor[i][j]);
			}
			printf("\n"); 
		}
	}
	else if(flag==0&&floor[x][y]!='0')
	{
		if(x==8) dfs(0,y+1);
		else dfs(x+1,y);
	}
	else
	{
		for(int i=1;flag==0&&i<=9;i++)
		{
			if(judge(x,y,i))
			{
				floor_b[x][y]=i+'0';
				hang[x][i+'0']=1;
				lie[y][i+'0']=1;
				ge[cnt_ge(x,y)][i+'0']=1;
				if(x==8) dfs(0,y+1);
				else dfs(x+1,y);
				hang[x][i+'0']=0;
				lie[y][i+'0']=0;
				ge[cnt_ge(x,y)][i+'0']=0;
				floor_b[x][y]='0';
			}
		}
	}
}


int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		flag=0;
		for(int i=0;i<9;i++)
		{
			hang[i].clear();
			lie[i].clear();
			ge[i].clear();
		}
		memset(floor,'0',sizeof(floor));
		memset(floor_b,'0',sizeof(floor_b));
		for(int i=0;i<9;i++)
		{
			for(int j=0;j<9;j++)
			{
				cin>>floor[i][j];
				if(floor[i][j]!='0')
				{
					hang[i][floor[i][j]]=1;
					lie[j][floor[i][j]]=1;
					ge[cnt_ge(i,j)][floor[i][j]]=1;
				}
			}
		}
	//	clock_t startTime=clock();
		dfs(0,0);
	//	clock_t endTime=clock();
	//	cout<<"用时:"<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<"s"<<endl; 
		
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值