请高人帮忙看看这个回朔数独算法有啥问题,谢谢
问题说明:这是以前用JAVA实现的数独算法,修改成C#版本。原本在JAVA上没什么问题,但是在.net上却会经常出现无解的情况。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace ConsoleApplication2
{
class sukodu
{
int[,] map = new int[9, 9];// 保存数独地图
ArrayList[,] usable = new ArrayList[9, 9];// 保存数独地图中每个元素的可选列表
Random random = new Random();
public void initMap(int[,] givenMap)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
map[i, j] = givenMap[i, j];
if (map[i, j] != 0)
{
usable[i, j] = new ArrayList();
usable[i, j].Add(map[i, j] + 100);// 参见方法说明
}
}
}
}
public int[,] createAndFill()
{
int direction = 1;
for (int num = 0; num < 81; )
{
Console.WriteLine(num+"");
// 如果回溯到第一个元素之前,说明此题无解,返回null
if (num < 0)
{
return null;
}
// i:每个地图元素的行编号(0序),j:每个地图元素的列编号(0序)
int i = num / 9;
int j = num % 9;
if (usable[i, j] == null)
{// -------说明地图上的这个元素还未曾被访问过
createList(i, j);
ArrayList src = usable[i, j];
if (src.Count == 0)
{// 卡死,不能进行,回溯
direction = 2;// 表示遍历方向为负方向
Console.WriteLine("第一次访问不能继续,回朔");
num--;
}
else
{// 可选列表中有元素,则随机选择一个,并将其从可选列表中删除
int randomIndex = Math.Abs(random.Next()) % src.Count;
// int[] value=(int[])src.ToArray(new int().GetType);
map[i, j] = (int)src[randomIndex];
src.RemoveAt(randomIndex);
direction = 1;
num++;
}
}// ----------说明地图上的这个元素还未曾被访问过
else
{// 可选列表不为空,曾经访问过 如果为空则说明还没有访问到这个点
if (usable[i, j].Count > 0
&& (int)((usable[i, j])[0]) > 10)
{
switch (direction)
{
case 1:
num++;
break;
case 2:
num--;
Console.WriteLine("原始数据,回朔");
break;
}
}
else
{
switch (direction)
{
case 1:
map[i, j] = 0;
createList(i, j);
ArrayList src = usable[i, j];
if (src.Count == 0)
{// 卡死,不能进行,回溯
Console.WriteLine("再次访问不能继续,回朔");
direction = 2;// 表示遍历方向为负方向
num--;
}
else
{// 可选列表中有元素,则随机选择一个,并将其从可选列表中删除
int randomIndex = Math.Abs(random.Next()) % src.Count;
map[i, j] = (int)src[randomIndex];
src.RemoveAt(randomIndex);
direction = 1;
num++;
}
break;
case 2:
src = usable[i, j];
if (src.Count == 0)
{
Console.WriteLine("可选列表已空,回朔");
direction = 2;// 表示遍历方向为负方向
num--;
}
else
{
int randomIndex = Math.Abs(random.Next()) % src.Count;
map[i, j] = (int)src[randomIndex];
src.RemoveAt(randomIndex);
direction = 1;
num++;
}
break;
}
}
}
}
return map;
}
--------------------编程问答-------------------- public int added(ArrayList list, int value)
{
for (int i = 0; i < list.Count; i++)
{
if ((int)list[i] == value)
{
return i;
}
}
return -1;
}
public void createList(int i, int j)
{
usable[i, j] = new ArrayList();
ArrayList src = usable[i, j];
// 初始化该元素位置可选列表,将1-9都添加进可选列表
for (int m = 1; m <= 9; m++)
{
src.Add(m);
}
// 判断与当前元素同行元素的值是否在可选列表之中
for (int col = 0; col < 9; col++)
{
int index = added(src, map[i, col]);
if (index != -1)
{// 当前值位于可选列表中,删除之
src.RemoveAt(index);
}
}
// 判断与当前元素同列行元素的值是否在可选列表之中
for (int row = 0; row < 9; row++)
{
int index = added(src, map[row, j]);
if (index != -1)
{// 当前值位于可选列表中,删除之
src.RemoveAt(index);
}
}
int cellI = i / 3;// 9宫格的行编号
int cellJ = j / 3;// 9宫格的列编号
int indexI = cellI * 3;// 9宫格左上角第一个元素的行编号
for (int a = 0; a < 3; a++)
{
int indexJ = cellJ * 3;// 9宫格左边第一列的列编号
for (int b = 0; b < 3; b++)
{
int index = added(src, map[indexI, indexJ]);
if (index != -1)
{
src.RemoveAt(index);// 当前值位于可选列表中,删除之
}
indexJ++;
}
indexI++;
}
}
static void Main(string[] args)
{ // int[,] map = new int[9, 9];
int[,] map ={
{5 , 9 , 0 , 3 , 0 , 0 , 1 , 0 , 6 },
{0 , 1 , 0 , 0 , 0 , 5 , 3 , 8 , 0 },
{0 , 0 , 6 , 9 , 0 , 1 , 0 , 0 , 0 },
{4 , 0 , 0 , 0 , 1 , 0 , 2 , 7 , 3 },
{2 , 5 , 0 , 0 , 3 , 7 , 0 , 0 , 0 },
{0 , 0 , 0 , 0 , 9 , 0 , 0 , 0 , 1 },
{9 , 6 , 5 , 1 , 0 , 0 , 8 , 0 , 0 },
{0 , 0 , 0 , 6 , 0 , 9 , 5 , 0 , 2 },
{1 , 0 , 8 , 0 , 0 , 3 , 0 , 9 , 0 }
};
sukodu sk = new sukodu();
sk.initMap(map);
long begin = Environment.TickCount;
map = sk.createAndFill();
long end = Environment.TickCount;
Console.WriteLine("计算时间 消耗:" + (end - begin) + "毫秒");
Console.WriteLine("#####################################");
//map = sk.map;
if (map != null)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (j % 3 == 2)
{
Console.Write(map[i, j] + " # ");
}
else if (j == 0)
{
Console.Write("# " + map[i, j] + " ");
}
else
{
Console.Write(map[i, j] + " ");
}
}
if (i % 3 == 2)
{
Console.WriteLine("\n#####################################");
}
else
{
Console.WriteLine();
}
}
}
else {
Console.WriteLine("抱歉,此迷题无解");
}
Console.ReadLine();
}
}
} --------------------编程问答-------------------- mathe好像专门写过这方面的算法文章。
http://blog.csdn.net/mathe/archive/2007/08/23/1755672.aspx
已经算是CSDN公认最好的算法了
常见的是用DLX算法来解决数独问题(忍不住又提起这个:《Dancing Links》,http://www-cs-faculty.stanford.edu/~knuth/preprints.html 能下载到),效率不错。
PS:
我也在研究这个算法中,可以一起讨论
补充:.NET技术 , 其他语言