【POJ】2676-Sudoku 【51Nod】1211-数独(DFS)

【POJ】2676-Sudoku

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 25200 Accepted: 11782 Special Judge
Description

Sudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smaller squares 3x3 as shown on the Figure. In some of the cells are written decimal digits from 1 to 9. The other cells are empty. The goal is to fill the empty cells with decimal digits from 1 to 9, one digit per cell, in such way that in each row, in each column and in each marked 3x3 subsquare, all the digits from 1 to 9 to appear. Write a program to solve a given Sudoku-task.

Input

The input data will start with the number of the test cases. For each test case, 9 lines follow, corresponding to the rows of the table. On each line a string of exactly 9 decimal digits is given, corresponding to the cells in this line. If a cell is empty it is represented by 0.
Output

For each test case your program should print the solution in the same format as the input data. The empty cells have to be filled according to the rules. If solutions is not unique, then the program may print any one of them.
Sample Input

1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107
Sample Output

143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127
Source

Southeastern Europe 2005

【51Nod】1211-数独

搜索
1211 数独
1 秒 131,072 KB 160 分 6 级题
数独游戏规则如下:在9 * 9的盘面上有些已知的数字及未知的数字,推理出所有未知的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。

有些局面存在多个解或无解,这属于不标准的数独。对于不标准的局面,输出No Solution。
输入
第1 - 9行,每行9个数中间用空格分隔,0表示该格子的数未知。
输出
如果局面是不标准的,输出No Solution,否则数据具体的解。
输入样例
0 6 0 5 9 3 0 0 0
9 0 1 0 0 0 5 0 0
0 3 0 4 0 0 0 9 0
1 0 8 0 2 0 0 0 4
4 0 0 3 0 9 0 0 1
2 0 0 0 1 0 6 0 9
0 8 0 0 0 6 0 2 0
0 0 4 0 0 0 8 0 7
0 0 0 7 8 5 0 1 0
输出样例
7 6 2 5 9 3 1 4 8
9 4 1 2 7 8 5 3 6
8 3 5 4 6 1 7 9 2
1 9 8 6 2 7 3 5 4
4 7 6 3 5 9 2 8 1
2 5 3 8 1 4 6 7 9
3 8 7 1 4 6 9 2 5
5 1 4 9 3 2 8 6 7
6 2 9 7 8 5 4 1 3

说明
做这题看的题目最早是【51Nod】1211-数独

本文解法主要面向【POJ】2676-Sudoku

本文代码主要表现为个人面对这题的思考和探索的过程,代码不一定都对

思路
深搜,给每个空格子依次填上1-9九个数字,依次判断是否满足三个条件(行,列,小方格不重复),直到所有空填完。

吐槽(提醒)
1.常听说cin,cout速度慢,之前做题少,没感觉。直到最近才渐渐意识到scanf(),printf()的好,这题就有这个细节问题导致超时的问题。

2.POJ 不支持用#include <bits/stdc++.h>

代码1
最早的尝试版本,在【51Nod】上20个数据过了15个,其他的TLE.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
const int maxn=1e5+10;
int a[9][9];
int b[9][9];
int ans=0;
int ck(int x,int y,int num)
{
	int m=x/3,n=y/3;
	for(int i=0;i<9;i++)
	{
		if(a[x][i]==num||a[i][y]==num)//判断该数字所在行列是否有值是相等的 
		return 0;
	}
	for(int i=3*m;i<3*(m+1);i++)
	{
		for(int j=3*n;j<3*(n+1);j++)//判断该数所在小方格是否有值是相等的 
		{
			if(a[i][j]==num)
			return 0; 
		} 
	}
	return 1;
}
void dfs(int x,int y)//x为行,y为列 
{
	if(ans>=2) return;
	if(x==9&&y==0)
	{
		ans++;
		if(ans>=2) return;
		memcpy(b,a,sizeof(a));
		return;
	}
	if(a[x][y])//当前位置已填空
	{
		if(y==8) dfs(x+1,0); 
		else dfs(x,y+1);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		if(!ck(x,y,i)) continue;//不满足条件跳出当前循环 
		a[x][y]=i;
		if(y==8) dfs(x+1,0); 
		else dfs(x,y+1);
		a[x][y]=0;
	} 
	
}
int main()
{
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	for(int i=0;i<9;i++)
	{
		for(int j=0;j<9;j++)
		{
			cin>>a[i][j];
		}
	} 
	
	dfs(0,0);
	if(ans>=2||ans==0) cout<<"No Solution"<<endl;
	else
	{
		for(int i=0;i<9;i++)
		{
			for(int j=0;j<9;j++)
			{
				if(j==8) cout<<b[i][j];
				else cout<<b[i][j]<<" ";
			}
			cout<<endl;
		}
	}
	return 0;
}

代码2
在借鉴学长代码后,写了代码2
学长代码直接就A了,168K 500MS
我的代码 Runtime Error
后来意思到是输入输出方式的问题(见代码注释掉的部分)
改成scanf(),printf()也过了,168K 657MS

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+10;
int row[10][10],col[10][10],grid[10][10];
int mapp[10][10];
int ans=0;
struct node{
	int x,y;
}gezi[82];

int dfs(int n)
{
	if(n>ans)//遍历到最后一个空格子的下一位时,填空完毕 
		return 1;
	for(int i=1;i<=9;i++)
	{
		int &a=row[gezi[n].x][i];
		int &b=col[gezi[n].y][i];
		int &c=grid[(gezi[n].x-1)/3*3+(gezi[n].y-1)/3][i];
		if(!a&&!b&&!c)
		{
			a=b=c=1;
			mapp[gezi[n].x][gezi[n].y]=i;
			if(dfs(n+1))
			return 1;
			a=b=c=0; 
		}
	}
	return 0;
}
int main()
{
	int t; cin>>t;
	while(t--)
	{
		ans=0;
		memset(row,0,sizeof(row));
		memset(col,0,sizeof(col));
		memset(grid,0,sizeof(grid));
		
		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++)
			{
				int k=(i-1)/3*3+(j-1)/3;
				//scanf("%1d",&mapp[i][j]);
				cin>>mapp[i][j]; 
				if(mapp[i][j])
				{
					row[i][mapp[i][j]]=1;
					col[j][mapp[i][j]]=1;
					grid[k][mapp[i][j]]=1;	
				}
				else
				{
					ans++;//记录空格子的数目 
					gezi[ans].x=i;
					gezi[ans].y=j;
				}
			}
		}
		
		dfs(1);//从第一个格子开始遍历
		
		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++)
			{
				//printf("%d",mapp[i][j]);
				cout<<mapp[i][j];
			}
			//printf("\n");
			cout<<endl;
		 } 
	}
	return 0;
}

代码3
上网查资料看到:https://blog.csdn.net/lyy289065406/article/details/6647977
提交通过,172K 422MS

//Memory Time 
//184K  422MS 
 
#include<iostream>
#include<cstring>
using namespace std;
 
int map[10][10]; //九宫格
 
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是否出现了
 
                     //(这里说明的字母不代表下面程序中的变量)
 
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++)   //枚举数字1~9填空
			if(!row[x][i] && !col[y][i] && !grid[k][i])
			{
				map[x][y]=i;
 
				row[x][i]=true;
				col[y][i]=true;
				grid[k][i]=true;
 
				if(y==9)
					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;
					grid[k][i]=false;
				}
				else
					return true;
			}
	}
	return false;
}
 
int main()
{
	int i;int j;
	int test;
	cin>>test;
	while(test--)
	{
		/*Initial*/
 
		memset(row,false,sizeof(row));
		memset(col,false,sizeof(col));
		memset(grid,false,sizeof(grid));
 
		/*Input*/
 
		char MAP[10][10];
		for(i=1;i<=9;i++)
			for(j=1;j<=9;j++)
			{
				cin>>MAP[i][j];
				map[i][j]=MAP[i][j]-'0';
 
				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;
					grid[k][ map[i][j] ]=true;
				}
			}
 
		/*Fill the Sudoku*/
 
		DFS(1,1);
		
		for(i=1;i<=9;i++)
		{
			for(j=1;j<=9;j++)
				cout<<map[i][j];
			cout<<endl;
		}
	}
	return 0;
}

代码4
基于代码3重写一遍,提交有错 Wrong Answer
暂时不想找错了,等过段时间再来看看吧(【51Nod】1211-数独解法,DLX算法什么的)
当然,我是知道的,这个过段时间,可能是最近几天,也可能是很久很久…

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+10;
int map1[10][10]; //九宫格
int ans=0;		  
int row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了
int col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了
int grid[10][10];   //grid[k][x] 标记在第k个3*3子格中数字z是否出现了

//本方法适合题目规定只需要输出一组解的题目,即POJ - 2676 
//找到一组解后就不停return1 
int dfs(int x,int y)
{
	if(x==10)
	{
		return 1;
	}
		
	int flag=0;
	if(map1[x][y])//当前位置已赋值 
	{
		if(y==9)
			flag=dfs(x+1,1);
		else
			flag=dfs(x,y+1);
			
		if(flag)  //回溯
			return 1;
		else
			return 0;
	}
	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]&&!grid[k][i])//三大判断条件中该数字都没重复 
			{
				map1[x][y]=i;			
				row[x][i]=col[y][i]=grid[k][i]=1; 
				
				if(y==9)
					flag=dfs(x+1,1);
				else
					flag=dfs(x,y+1);
					
				if(!flag)
				{
					map1[x][y]=0;					
					row[x][i]=col[y][i]=grid[k][i]=0;		
				}
				else
				return 1;
			}
		 } 
	} 
	return 0;
}
int main()
{
	int test;
	cin>>test;
	while(test--)
	{
		memset(row,0,sizeof(row));
		memset(col,0,sizeof(col));
		memset(grid,0,sizeof(grid));
		
		for(int i=1;i<=9;i++)
			for(int j=1;j<=9;j++)
			{
				printf("%d",&map1[i][j]);			
				if(map1[i][j])
				{
					int k=3*((i-1)/3)+(j-1)/3+1;//
					row[i][map1[i][j]]=1; 
					col[j][map1[i][j]]=1; 
					grid[k][map1[i][j]]=1; 
				}
			}
			
		dfs(1,1);//从位置(1,1)开始深搜
		

		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++)
			{
				printf("%d",&map1[i][j]);
			}
			printf("\n");
		}	
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值