8数字拼图(A星算法)
8数字拼图(A星算法)
代码
using System.Collections.Generic;
using System;
namespace PinTu
{
class PinTU
{
/// <summary>
/// 结点类型
/// </summary>
class Node
{
//结点状态表
public List<int> p;
//空格位置
public int Spac;
//父结点标识
public int last;
//结点数码位置表s
public List<int> u;
//估价函数
public int f;
public int g;
public int h;
public Node()
{
p = new List<int>();
u = new List<int>();
Spac = 0;
last = 0;
f = 0;
g = 0;
h = 0;
}
public Node Clone()
{
Node node = new Node();
node.p = new List<int>();
for (int i = 0; i < this.p.Count; i++)
{
node.p.Add(this.p[i]);
}
node.Spac = this.Spac;
node.last = this.last;
node.u = new List<int>();
for (int i = 0; i < this.u.Count; i++)
{
node.u.Add(this.u[i]);
}
node.f = this.f;
node.g = this.g;
node.h = this.h;
return node;
}
};
List<Node> Nodes = new List<Node>();
//空队列
Node EndNode = new Node();
//目标结点
Node Temp1 = new Node();
//临时结点
int head = 0;
//队列头指针
int tail = 0;
//队列尾指针
int[] dir = new int[4];
//空格移动增量
string s = null;
//字符串变量
//int[] dis = new int[82];
List<int> dis = new List<int>();
//两个结点同一数码的相对距离表
//目标结点数码位置表
//int[] v = new int[9];
List<int> v = new List<int>();
int counts = 0;
//int MoveStep = 0;
List<int> num = new List<int>();
//int tmp = 0;
//保存结点状态,准备输出
private void DispNode(Node Temp)
{
counts = counts + 1;
for (int i = 0; i <= 8; i++)
{
s = s + Convert.ToString(Temp.p[i]) + " ";
if ((i + 1) % 3 == 0)
s = s + "\n";
}
s = s + "\n";
}
//确定搜索路径
private void DispPath(int k)
{
k = Nodes[k].last;
if (k == -1)
return;
DispPath(k);
DispNode(Nodes[k]);
}
//移动空格
private bool SpacMove(Node T, int k)
{
bool ret = false;
int oldspac = 0;
//如果移出边界返回False
if (k == 0)
if (T.Spac < 3)
return ret;
if (k == 1)
if (T.Spac % 3 == 0)
return ret;
if (k == 2)
if (T.Spac % 3 == 2)
return ret;
if (k == 3)
if (T.Spac > 5)
return ret;
//记录原来的空格位置
oldspac = T.Spac;
//新空格位置
T.Spac = T.Spac + dir[k];
//移动空格(交换数码)
T.p[oldspac] = T.p[T.Spac];
T.p[T.Spac] = 0;
//交换数码的位置
T.u[0] = T.Spac;
T.u[T.p[oldspac]] = oldspac;
//返回True
return true;
}
//判断两个结点是否相同
private bool Equal(Node T1, Node T2)
{
for (int i = 0; i <= 8; i++)
{
if (T1.p[i]!=T2.p[i])
{
return false;
}
}
return true;
//return T1.p.Equals(T2.p);
}
//查找重复结点序号
private int Rept(Node T)
{
int i = 0;
for (i = 0; i <= tail; i++)
{
if (Equal(T, Nodes[i]))
return -1;
}
return i;
}
//计算估价函数f
private void Calcuf(Node Temp)
{
Temp.h = 0;
for (int i = 1; i <= 8; i++)
{
Temp.h = Temp.h + dis[Temp.u[i] * 9 + v[i]];
}
Temp.g = Temp.g + 1;
Temp.f = Temp.g + Temp.h;
}
//将结点按f大小插入队列(开启列表)
private void Sortf(Node T)
{
int i = 0;
for (i = head + 1; i <= tail; i++)
{
if (T.f < Nodes[i].f)
break; // TODO: might not be correct. Was : Exit For
}
Nodes.Insert(i, T);
}
//A*搜索法
public void Astar()
{
int i = 0;
int k = 0;
//队列头、尾指针指向队列头(初始结点)
head = 0;
tail = 0;
//计算初始结点的f
Calcuf(Nodes[0]);
//队列不空则循环
while (head <= tail)
{
//Text1 = head;
//DoEvents
//尝试向上、左、右、下移动空格
for (i = 0; i <= 3; i++)
{
//取队列头结点
Node Temp = new Node();
Temp = Nodes[head].Clone();
//如果是目标结点
if (Equal(Temp, EndNode))
{
//确定搜索路径
DispPath(head);
//目标结点
DispNode(Nodes[head]);
//退出
return;
}
//若可以扩展则
if (SpacMove(Temp, i))
{
//记录父结点标识
Temp.last = head;
//计算f
Calcuf(Temp);
//计算重复结点号
k = Rept(Temp);
//若不重复则
if (k > tail)
{
//按f大小插入队列
Sortf(Temp);
//移动队列尾指针
tail = tail + 1;
//否则如果与待扩展结点重复
}
else if (head <= k & k <= tail)
{
//则比较两结点的g,保留g小的结点
if (Nodes[k].g > Temp.g)
Nodes[k] = Temp;
}
}
}
//一个结点不能再扩展,放入关闭列表,并指向下一结点
head = head + 1;
}
}
//初始化
public void Init()
{
int i = 0;
int j = 0;
int k = 0;
//初始状态数据
int[] numberData = new int[] { 8, 7, 6, 5, 4, 3, 2, 1, 0 };
//目标状态数据
int[] numberData1 = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8 };
//初始结点
Nodes.Add(new Node());
//读入初始状态数据,记录其下标
Node n = Nodes[0];
n.p = new List<int>();
n.u = new List<int>(numberData);
for (i = 0; i <= 8; i++)
{
n.p.Add(numberData[i]);
n.u[n.p[i]] = i;
}
n.Spac = n.u[0];
n.last = -1;
n.f = 0;
n.g = 0;
n.h = 0;
//读入目标状态数据,记录其下标
EndNode.p = new List<int>();
v = new List<int>(numberData1);
for (i = 0; i <= 8; i++)
{
EndNode.p.Add(numberData1[i]);
v[EndNode.p[i]] = i;
}
EndNode.Spac = v[0];
EndNode.last = -1;
EndNode.f = 0;
EndNode.g = 0;
EndNode.h = 0;
//空格移动增量数据
for (i = 0; i <= 3; i++)
{
dir[i] = i * 2 - 3;
}
//计算两个结点同一数码的相对距离
dis = new List<int>();
for (i = 0; i <= 80; i++)
{
j = i / 9;
k = i % 9;
dis.Add( Math.Abs(j / 3 - k / 3) + Math.Abs(j % 3 - k % 3));
}
s = "";
counts = 0;
}
public string Test()
{
Init();
Astar();
return "搜索结点:" + head + " \n移动最少步:" + (counts - 1) + "\n" + s;
}
}
}

浙公网安备 33010602011771号