一个数独问题的算法(已更新,提供一个简单算法,欢迎拍砖)
2006-08-25 14:54
609 查看
前段时间出差在外闲得无事看到一个数独问题。有三题,脑子不好使,只做出前两题。想想不如用程序来实现。
我先把题放出来大家有兴趣研究一下。
规则:
在9*9的格子中用1到9填满格子:
每一行都要用到1~9,位置不限;
每一列都要用到1~9,位置不限;
每3*3格子都要用到1~9,位置不限;
我的算法思想比较简单:穷举法,递归。
1、初始化:
新建两个数组A[9,9],B[9,9],他们的初始值都一样。
public static int[,,] A = new int[9,9,9];
public static int[,] B = new int[9,9];
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
A[i,j] = 0;
A[0,1]=6;
A[0,4]=1;
A[0,5]=7;
………………
A[8,3]=5;
A[8,4]=4;
A[8,7]=8;
A[8,8]=6;
for(int m=0;m<9;m++)
for(int n=0;n<9;n++)
B[m,n] = 0;
B[0,1]=6;
B[0,4]=1;
B[0,5]=7;
………………
B[8,3]=5;
B[8,4]=4;
B[8,7]=8;
B[8,8]=6;
递归过程:
public void JudgeNumber(int x,int y)
{
if(x<9&&y<9) //判断数组下标范围
{
if(A[x,y] == 0||A[x,y] != B[x,y]) //如果数组的值为零或者取得的值不等于B的值
{
for(int i=1;i<10;i++)
{
A[x,y] = i; //循环付值
if(Pass(x,y)) //判断条件
{
if(Victory()) //成功
{
printShuzu();
return ;
}
if(y<8) //判断下一个数
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
A[x,y] = 0; //失败之后把值设为零,以便继续判断
}
else //判断下一个数
{
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
public bool Pass(int i,int j)
{
//判断横竖有无重复
for(int b=0;b<9;b++)
{
if(b!=i)
if(A[i,j] == A[b,j])
return false;
if(b!=j)
if(A[i,j] == A[i,b])
return false;
}
//判断*3有无重复
int q0 = (i/3)*3;
int k0 = (j/3)*3;
int q1 = (i/3+1)*3;
int k1 = (j/3+1)*3;
for(int q=q0;q<q1;q++)
for(int k=k0;k<k1;k++)
if(q!=i&&k!=j)
if(A[i,j] == A[q,k])
return false;
return true;
}
/// <summary>
/// 在Pass情况下如果整个数组无0表示成功求解
/// </summary>
/// <returns></returns>
public bool Victory()
{
bool ax=false;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
if( A[i,j] != 0)
ax =true;
else
return false;
}
return ax;
}
本算法的问题:
1.穷举取值过多。不必从1~9全部取
2.成功后在递归里面不能跳出。
对问题1的改进:
1.新建3维数组A[9,9,9]
2初始判断,获取该位置可取值的范围
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
int[] B = new int[9];
for(int d=0;d<9;d++)
B[d] = d+1;
if(A[i,j,0]==0)
{
for(int a=0;a<9;a++)
{
A[i,j,0] = B[a];
for(int b=0;b<9;b++)
{
if(b!=i)
if(A[i,j,0] == A[b,j,0])
B[a]=0;
if(b!=j)
if(A[i,j,0] == A[i,b,0])
B[a]=0;
}
int q0 = (i/3)*3;
int k0 = (j/3)*3;
int q1 = (i/3+1)*3;
int k1 = (j/3+1)*3;
for(int q=q0;q<q1;q++)
for(int k=k0;k<k1;k++)
if(q!=i&&k!=j)
if(A[i,j,0] == A[q,k,0])
B[a]=0;
A[i,j,0] = 0;
}
}
}
3.更改判断部分.
public void JudgeNumber(int x,int y)
{
if(x<9&&y<9)
{
if(A[x,y,0] == 0||A[x,y,0] != B[x,y])
{
for(int i=1;i<9;i++)//更改部分
{
if(A[x,y,i]!=0)//更改部分
{
A[x,y,0] = A[x,y,i];//更改部分
if(Pass(x,y))
{
if(Victory())
{
printShuzu();
//return ;
}
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
A[x,y,0] = 0;
}
else
{
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
我先把题放出来大家有兴趣研究一下。
8 | 5 | 7 | 1 | |||||
1 | 9 | 2 | ||||||
6 | 2 | |||||||
5 | 6 | 9 | ||||||
2 | 4 | 5 | 8 | |||||
8 | 1 | 2 | ||||||
4 | 9 | |||||||
4 | 6 | 5 | 7 | |||||
5 | 8 | 9 | 1 |
5 | 2 | |||||||
1 | 9 | 6 | 3 | |||||
3 | 5 | 7 | 6 | |||||
6 | 1 | 4 | 7 | |||||
7 | 2 | 6 | 4 | |||||
5 | 3 | 8 | 6 | |||||
9 | 7 | 8 | 3 | |||||
5 | 8 | 3 | 9 | |||||
8 | 7 |
6 | | | 1 | 7 | | | | |
| 1 | 9 | 3 | 6 | | | | |
| | | | | | | | 4 |
| 5 | | | | 2 | | | 8 |
8 | | 1 | | | | 7 | | 2 |
2 | | | 7 | | | | 6 | |
6 | | | | | | | | |
| | | | 7 | 6 | 5 | 3 | |
| | | 5 | 4 | | | 8 | |
在9*9的格子中用1到9填满格子:
每一行都要用到1~9,位置不限;
每一列都要用到1~9,位置不限;
每3*3格子都要用到1~9,位置不限;
我的算法思想比较简单:穷举法,递归。
1、初始化:
新建两个数组A[9,9],B[9,9],他们的初始值都一样。
public static int[,,] A = new int[9,9,9];
public static int[,] B = new int[9,9];
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
A[i,j] = 0;
A[0,1]=6;
A[0,4]=1;
A[0,5]=7;
………………
A[8,3]=5;
A[8,4]=4;
A[8,7]=8;
A[8,8]=6;
for(int m=0;m<9;m++)
for(int n=0;n<9;n++)
B[m,n] = 0;
B[0,1]=6;
B[0,4]=1;
B[0,5]=7;
………………
B[8,3]=5;
B[8,4]=4;
B[8,7]=8;
B[8,8]=6;
递归过程:
public void JudgeNumber(int x,int y)
{
if(x<9&&y<9) //判断数组下标范围
{
if(A[x,y] == 0||A[x,y] != B[x,y]) //如果数组的值为零或者取得的值不等于B的值
{
for(int i=1;i<10;i++)
{
A[x,y] = i; //循环付值
if(Pass(x,y)) //判断条件
{
if(Victory()) //成功
{
printShuzu();
return ;
}
if(y<8) //判断下一个数
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
A[x,y] = 0; //失败之后把值设为零,以便继续判断
}
else //判断下一个数
{
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
public bool Pass(int i,int j)
{
//判断横竖有无重复
for(int b=0;b<9;b++)
{
if(b!=i)
if(A[i,j] == A[b,j])
return false;
if(b!=j)
if(A[i,j] == A[i,b])
return false;
}
//判断*3有无重复
int q0 = (i/3)*3;
int k0 = (j/3)*3;
int q1 = (i/3+1)*3;
int k1 = (j/3+1)*3;
for(int q=q0;q<q1;q++)
for(int k=k0;k<k1;k++)
if(q!=i&&k!=j)
if(A[i,j] == A[q,k])
return false;
return true;
}
/// <summary>
/// 在Pass情况下如果整个数组无0表示成功求解
/// </summary>
/// <returns></returns>
public bool Victory()
{
bool ax=false;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
if( A[i,j] != 0)
ax =true;
else
return false;
}
return ax;
}
本算法的问题:
1.穷举取值过多。不必从1~9全部取
2.成功后在递归里面不能跳出。
对问题1的改进:
1.新建3维数组A[9,9,9]
2初始判断,获取该位置可取值的范围
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
int[] B = new int[9];
for(int d=0;d<9;d++)
B[d] = d+1;
if(A[i,j,0]==0)
{
for(int a=0;a<9;a++)
{
A[i,j,0] = B[a];
for(int b=0;b<9;b++)
{
if(b!=i)
if(A[i,j,0] == A[b,j,0])
B[a]=0;
if(b!=j)
if(A[i,j,0] == A[i,b,0])
B[a]=0;
}
int q0 = (i/3)*3;
int k0 = (j/3)*3;
int q1 = (i/3+1)*3;
int k1 = (j/3+1)*3;
for(int q=q0;q<q1;q++)
for(int k=k0;k<k1;k++)
if(q!=i&&k!=j)
if(A[i,j,0] == A[q,k,0])
B[a]=0;
A[i,j,0] = 0;
}
}
}
3.更改判断部分.
public void JudgeNumber(int x,int y)
{
if(x<9&&y<9)
{
if(A[x,y,0] == 0||A[x,y,0] != B[x,y])
{
for(int i=1;i<9;i++)//更改部分
{
if(A[x,y,i]!=0)//更改部分
{
A[x,y,0] = A[x,y,i];//更改部分
if(Pass(x,y))
{
if(Victory())
{
printShuzu();
//return ;
}
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
A[x,y,0] = 0;
}
else
{
if(y<8)
JudgeNumber(x,y+1);
else
JudgeNumber(x+1,0);
}
}
}
相关文章推荐
- 关于gae不能更新的问题,提供一个简单的解决方案
- 火车运煤问题 - 增加一个简单算法实现
- 想设计一个简单的RSS在线阅读程序,欢迎大伙提供意见
- 一个简单的随机数字串函数,欢迎拍砖改进
- 《叩响C#之门》园友提供的附录(征集中,欢迎提意见)读取流时应注意的一个问题
- 一天一个算法题-简单的-递归-猴子吃桃问题
- 由一个简单算法想到的程序员素养问题
- 提供一个逻辑问题的算法!(最近打的大家参考一下)
- 阶乘问题(大数阶乘)简单 n! (一个大数与一个小数相乘的算法 、一个大数与一个小数的除法算法 *【模板】 )
- 由一个简单算法想到的程序员素养问题
- 一个简单的e-mail校验函数,欢迎拍砖改进
- HashMap与Hashtable的区别是面试中经常遇到的一个问题。这个问题看似简单,但如果深究进去,也能了解到不少知识。本文对两者从来源、特性、算法等多个方面进行对比总结。力争多角度、全方位的展示二者的不同,做到此问题的终结版。
- 数独问题的一种简单算法代码实现
- 一个简单的取用户真实IP函数[B/S],欢迎拍砖改进
- 一个简单的PHP算法问题!
- 【素养】由一个简单算法想到的程序员素养问题
- 每日一道算法题2——定义一个栈,提供一个返回栈里最小元素方法
- 关于数据库的一个统计算法的优化,欢迎大家来讨论(一定要赖心看的)
- java框架搭配思考(个人文档更新)欢迎拍砖。。。
- 一个看似简单的问题(#if与#ifdef的区别)