你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
回溯法解数独问题(三)
 

试探/回溯步进调整。

步进就是当本位置设置的值符合约束函数的约束,需要进入到下一个位置的条件设定,或者本位置的所有可能都已经遍历未发现符合条件的解,需要回溯到上一个位置,此时调整数组位置就称之为步进。本程序的步进调整按照4维数组的维数从后向前依次调整的方式进行调整,也就是按照每个小九宫中的每个元素从列到行依次步进,每个小九宫在大九宫中也按照此原则依次步进。

 

        /// <summary>

        /// 调整回溯值

        /// </summary>

        /// <param name="i">原始i</param>

        /// <param name="j">原始j</param>

        /// <param name="k">原始k</param>

        /// <param name="l">原始l</param>

        /// <param name="addition">l的步进值,正为后移,负为回溯</param>

 

        private void ResetIJKL(ref int i, ref int j, ref int k, ref int l,  int addition)

        {

            int i1 = i;

            int j1 = j;

            int k1 = k;

            int l1 = l;

 

            int l2 = l1 + addition;

 

            while (true)

            {

                if (l2 >= COLUMNS) //l到达尾部

                {

                    l2 = 0;

                    k1++;

                }

                else

                    if(l2<0) //l到达头部

                {

                    l2 = COLUMNS - 1;

                    k1--;

                }

               

               

 

 

在步进中会遇到几个问题,第一是数组越界,如果步进(含试探步进和回溯)到下一个位置恰好超出了大小九宫的行、列尽头,则按照上述代码的方式依次调整位置。

 

               

                if (i1 >= ROWS||i1<0) //i到达头部或者尾部 结束

                {

                    i = i1;

                    j = j1;

                    k = k1;

                    l = l2;

                    return;

                }

 

 

    在步进中,遇到的第二个问题就是步进到整个数组的开头或者尽头。此时将不再步进,返回原值。

 

 

                if (bk_sd[i1, j1, k1, l2] == true) //如果回溯的上一个位置为不可移动的固定位,则继续步进

                    l2 += addition;

                else

                    break;

            }

        }

 

在步进中会遇到第三个问题是步进到的下一个位置恰好是初始设置,该位置的值不能改变,因此步进将跳过该位置,步进到该位置前或者后一个位置去。

 

回溯法获得数独问题的一个解。

 

        /// <summary>

        /// 获得数独的一个解

        /// </summary>

        /// <returns></returns>

 

        public int ComputeShudo()

        {

            ///回溯法步骤计数,当初始状态的所有可能全部遍历

            ///则该问题无解

            int step = 0;

            int i = 0;

            int j = 0;

            int k = 0;

            int l = 0;

 

            bool IsInSmall = false;//当前元素的值是否存在于小九宫中

            bool IsInRow = false;//当前元素的值是否存在于行中

            bool IsInColumn = false;//当前元素的值是否存在于列中

 

            while ((step >= 0 && process_sd[i, j, k, l] <= MAX_NUM) && (i < ROWS && j < COLUMNS && k < ROWS && l < COLUMNS))

            //回溯循环结束的条件(无解条件):1,数组越界;2,当前位置的值超出0-9的范围;3,回溯步骤归零(回溯到开始状态)

            {

 

                if (bk_sd[i, j, k, l])//当前格为固定格

                {

                    ResetIJKL(ref i, ref j, ref k, ref l,1);

                }

                else//当前格为非固定格

                {

                    while (process_sd[i, j, k, l]++ <= MAX_NUM)//当 当前元素的值和其他已知的值都不冲突时,设置值,否则当前元素的值+1继续测试

                    {

                        IsInSmall = CheckInSmall(i, j, k, l, ref process_sd);

                        if (IsInSmall)

                            continue;

                        IsInRow = CheckInRow(i, j, k, l, false, ref process_sd);

                        if (IsInRow)

                            continue;

                        IsInColumn = CheckInColumn(i, j, k, l, false, ref process_sd);

                        if (IsInColumn)

                            continue;

 

                        break;

                    }

                    if (process_sd[i, j, k, l] <= MAX_NUM)//当前位置所安置的数值位于0-9之间时,准备下一轮试探

                    {

                        if (step == 80 - init_count)//当所置的数值的个数达到了规定的个数,则回溯算法结束,获得一个解

                        {

                            break;

                        }

                        step++;

                        ResetIJKL(ref i, ref j, ref k, ref l,1);

                    }

                    else //当前位置所安置的数值超过0-9的范围外时,准备下一轮回溯

                    {

                        process_sd[i, j, k, l] = 0;

                        step--;

                        ResetIJKL(ref i, ref j, ref k, ref l, -1);

                    }

                }

 

                if (i >= ROWS)

                {

                    break;

                }

            }

 

                return step;

            }

 

回溯法获得数独问题的一个解。

    如前所述,用回溯法获得的解并非该问题的全部解,为了获得该问题的全部解。在获得一个解的方法基础上,对部分代码进行适当调整从而得到全解方法。

    引入一个ArrayList型的对象all_shudo用来存放每一个获得的数独解。

 

/// <summary>

/// 数独所有解的集合

/// </summary>

private ArrayList all_shudo=new ArrayList ();

 

同时修改单解方法中的以下部分。

 

if (step == 80 - init_count)//当所置的数值的个数达到了规定的个数,则获得一个解,将该解置入解集中,同时打印该解,同时在该解的基础上开始回溯,以求得下一个解

{

all_shudo.Add(process_sd.Clone());

ResetIJKL(ref i, ref j, ref k, ref l, -1);

step--;

continue;

 

}

 

当获得一个解以后,将这个解存入all_shudo中,同时进行回溯步进,通过改变上一个位置的值进行试探,从而达到回溯到下一个可能解的目的。

 

四、结论

 

    回溯法通过约束条件的筛选,在所有解中筛除掉不可能的解,从而获得问题的一个或者全部解。通过运用回溯法可以获得数独的一个解或者全部解。

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089