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