回溯解决八数码问题(深度优先)

不懂c#怎么搞对象链表,就用对象数组来实现回溯。这里用到线程控制,单步输出解的每一步状态(即线程的挂起和继续)。这个是无序搜索的,可以考虑加上加权回溯试探。
using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;


namespace bashuma
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
        }
        //0 1 2
        //3 4 5
        //6 7 8
        static Thread theradsuanfa2;
        static int[] xulie = { 0,1,2,5,8,7,6,3};//顺时针产生的8个数序列下标

        public bool Ispass_strchongfuzifu(string str)//判断是否通过 字符串中是否有重复字符 验证
        {
            int i , j;
            for (i = 0; i < str.Length; i++)
            {
                for (j = i + 1; j < str.Length; j++)
                {
                    if (str[i] == str[j])
                    {
                        return false;
                    }
                }
            }


            return true;
        }


        public int Qiunixushu(string str)//求逆序数
        {
            int count = 0;
            int i, j;


            //for (i = 0; i < str.Length; i++)//求逆序方法1,感觉有点问题
            //{
            //    for (j = i + 1; j < str.Length; j++)
            //    {
            //        if (str[i] > str[j])
            //        {
            //            count++;
            //        }
            //    }
            //}
            for (i = 1; i < str.Length; i++)//求逆序方法2
            {
                for (j = 0; j < i; j++)
                {
                    if (str[j] > str[i])//如果前面的数比前面的大
                        count++;
                }
            }


            return count;
        }


        public bool Isyoujie(string strchushi, string strmubiao)//判断是否有解
        {
            strchushi = strchushi.Replace("0","");
            strmubiao = strmubiao.Replace("0","");


            int ichushi=Qiunixushu(strchushi);
            int imubiao=Qiunixushu(strmubiao);
            if( (ichushi&1) == (imubiao&1) )//如果逆序数相同 有解
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        private void button2_Click(object sender, EventArgs e)
        {
            theradsuanfa2 = new Thread(new ThreadStart(suanfa2));
            theradsuanfa2.Start();
            //suanfa2();

        }


        void suanfa2()
        {
            int Maxshendu = 36;
            string strchushi = textBox1.Text;//string strchushi ="123456780";
            string strmubiao = textBox2.Text;//string strmubiao ="123456078";
            string strmaxshendu = textBox3.Text;


            if (!string.IsNullOrWhiteSpace(strmaxshendu))
            {
                Maxshendu = Convert.ToInt16(strmaxshendu);
            }


            if (!Isyoujie(strchushi, strmubiao))
            {
                MessageBox.Show("无解");
                return;
            }
            if (!(Ispass_strchongfuzifu(strchushi) && Ispass_strchongfuzifu(strmubiao)))
            {
                MessageBox.Show("初始或目标字符串有重复数字");
                return;
            }

            
            int[,] xiangliang = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };//上 右 下 左
            Duixiang[] duixiangarr = new Duixiang[500];
            int shendu = 0;
            int lingx = 0, lingy = 0;
            char[,] dangqian = new char[3, 3];
            char[,] mubiao = new char[3, 3];


            Stringtoarr(strchushi, ref dangqian);
            Stringtoarr(strmubiao, ref mubiao);
            find0(dangqian, ref lingx, ref lingy);


            duixiangarr[0] = new Duixiang();
            duixiangarr[0].Setjuzhen(dangqian);
            duixiangarr[0].Setxiangliangxiabiao(0);
            duixiangarr[0].Setlingzuobiao(lingx, lingy);



            while (true)
            {
                if (shendu < 0)
                {
                    //回溯完成
                    MessageBox.Show("回溯完成");
                    break;
                }




                if (Isjuzhenxiangtong(duixiangarr[shendu].juzhen, mubiao))
                {
                    MessageBox.Show("找到解");
                    for (int i = 0; i <= shendu; i++)
                    {
                        string str = "";
                        Zhuanhuantolabstring(ref str, duixiangarr[i].juzhen);
                        Thread.CurrentThread.Suspend();
                        //Thread.Sleep(2000);
                        //MessageBox.Show("");
                        label4.Text = str;


                    }
                    //找到一个解
                    break;
                }


                if (duixiangarr[shendu].xiangliangxiabiao > 3 || shendu > Maxshendu)//试探下标大于取值上限 或深度大于Maxshendu
                {
                    shendu--;
                    if (shendu < 0)//深度小于0 跳出
                    {
                        break;
                    }
                    duixiangarr[shendu].xiangliangxiabiao++;
                }
                else
                {
                    if (Ispassyuejie(duixiangarr[shendu].lingzuobiao, xiangliang, duixiangarr[shendu].xiangliangxiabiao))//是否通过越界检测
                    {
                        char[,] arrtemp = new char[3, 3];
                        Fuzhijuzhen(ref arrtemp, duixiangarr[shendu].juzhen);
                        Yiwei(ref arrtemp, duixiangarr[shendu].lingzuobiao, xiangliang, duixiangarr[shendu].xiangliangxiabiao);
                        if (Ispassxiangtongjuzhen(duixiangarr, shendu, arrtemp))
                        {
                            int[] ling = new int[2];
                            ling[0] = duixiangarr[shendu].lingzuobiao[0] + xiangliang[duixiangarr[shendu].xiangliangxiabiao, 0];
                            ling[1] = duixiangarr[shendu].lingzuobiao[1] + xiangliang[duixiangarr[shendu].xiangliangxiabiao, 1];


                            shendu++;
                            duixiangarr[shendu] = new Duixiang();
                            duixiangarr[shendu].Setjuzhen(arrtemp);
                            duixiangarr[shendu].Setxiangliangxiabiao(0);
                            duixiangarr[shendu].Setlingzuobiao(ling[0], ling[1]);
                        }
                        else
                        {
                            duixiangarr[shendu].xiangliangxiabiao++;
                        }
                    }
                    else
                    {
                        duixiangarr[shendu].xiangliangxiabiao++;
                    }
                }

            }


        }
        bool Ispassyuejie(int [] lingzhuobiao, int [,] xiangliang ,int xiangliangxiabiao)//是否通过越界检测
        {
            int x = 0, y=0;
            x = lingzhuobiao[0] + xiangliang[ xiangliangxiabiao, 0];
            y = lingzhuobiao[1] + xiangliang[ xiangliangxiabiao, 1];
            if (x < 0 || x > 2)
                return false;
            if (y < 0 || y > 2)
                return false;
            return true;
        }


        bool Ispassxiangtongjuzhen(Duixiang [] duixiangarr, int dangqianshendu ,char [,] arrtemp)//通过对象数组相同矩阵检测
        {
            for (int i = 0; i <= dangqianshendu; i++)
            {
                if (Isjuzhenxiangtong(arrtemp, duixiangarr[i].juzhen))
                    return false;
            }
            return true;
        }
        bool Isjuzhenxiangtong(char[,] dangqian, char[,] mubiao)//两个矩阵是否相同
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (dangqian[i,j] != mubiao[i,j])
                    {
                        return false;
                    }
                }
            }
            return true;
        }


        public void Stringtoarr(string str, ref char[,]arr)//字符串转到3*3字符矩阵
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    arr[i,j]=str[3*i+j];
                }
            }
        }


        void Fuzhijuzhen(ref char[,] mubiao, char[,] yuan)//复制矩阵
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    mubiao[i, j] = yuan[i , j];
                }
            }
        }


        void Yiwei(ref char[,] juzhen, int[] lingzhuobiao, int[,] xiangliang, int xiangliangxiabiao)//把0按向量移位
        {
            int x=lingzhuobiao[0] + xiangliang[ xiangliangxiabiao, 0];
            int y=lingzhuobiao[1] + xiangliang[ xiangliangxiabiao, 1];
            char c=juzhen[x,y];
            juzhen[x,y]=juzhen[lingzhuobiao[0], lingzhuobiao[1]];
            juzhen[lingzhuobiao[0], lingzhuobiao[1]] = c;
        }


        void Zhuanhuantolabstring(ref string str, char [,] arr)//吧矩阵转为lab的文本string输出
        {
            str = "";
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    str+=" "+arr[i,j];
                }
                str += "\n";
            }


        }
        public void find0(char[,]arr,  ref int x, ref int y)//找矩阵中0值的坐标
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (arr[i, j] == '0')
                    {
                        x = i;
                        y = j;
                    }
                }
            }
        }


        private void button3_Click(object sender, EventArgs e)
        {
            theradsuanfa2.Resume();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//可以解决线程间调用无效的问题。
            // 加入这句代码以后发现程序可以正常运行了。
            //这句代码就是说在这个类中我们不检查跨线程的调用是否合法(如果没有加这句话运行也没有异常,那么说明系统以及默认的采用了不检查的方式)。
            //然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,
            //也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异常,我们通常都会去检查。
            //如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。
        }


    }


    
    public class Duixiang
    {
        public char[,] juzhen = new char[3, 3];
        public int xiangliangxiabiao;
        public int[] lingzuobiao = new int[2];


        public void Setjuzhen(char[,] arr)//设置矩阵
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    this.juzhen[i,j]=arr[i,j];
                }
            }
        }
                
        public void Setxiangliangxiabiao(int sub)//设置向量
        {
            this.xiangliangxiabiao = sub;
        }


        public void Setlingzuobiao(int x, int y)//设置0坐标
        {
            this.lingzuobiao[0] = x;
            this.lingzuobiao[1] = y;
        }
    }


    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值