八数码 问题

小曦子 2009-05-04 10:27:47

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;


namespace pingtu
{
public class AI
{
public const int WinnerCode = 1;//完成全部排列时返回的标志
private Stack<DataCon> st;
public long total; //一共走过多少结点数
public long same; //记录走过的相同 的结点数
private Dictionary<long, int[,]> totalDir;//记录所有不同的结点图
public Stack<DataCon> dict;//用来记录一个完整的走法图表列
private int[,] start;
private int[,] end;
private int MaxDepth;
public float time;
private int depth;

/// <summary>
/// 用来初始化数据
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="depth"></param>
private void Init(int[,] start, int[,] end, int depth1)
{
totalDir = new Dictionary<long, int[,]>();
st = new Stack<DataCon>();
depth = 0;
total = 0;
same = 0;
time = 0;
dict = new Stack<DataCon>();
this.start = start;
this.end = end;
this.MaxDepth = depth1;
}

/// <summary>
/// 判断有无解法法法!
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
private bool ExistAns(int[,] start, int[,] end)
{
int sequence_start = 0, sequence_end = 0;
for (int i = 0; i < 9; i++)
{
if (start[i / 3, i % 3] != 0)
{
for (int j = i + 1; j < 9; j++)
{
if (start[j / 3, j % 3] != 0 && start[j / 3, j % 3] < start[i / 3, i % 3])
sequence_start++;
}
}
if (end[i / 3, i % 3] != 0)
{
for (int j = i + 1; j < 9; j++)
{
if (end[j / 3, j % 3] != 0 && end[j / 3, j % 3] < end[i / 3, i % 3])
sequence_start++;
}
}
}
return (sequence_start + sequence_end) % 2 == 0;
}

/// <summary>
/// 判断是否完成所有排列
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
private bool IsSuccess(int[,] start, int[,] end)
{
for (int i = 0; i < 9; i++)
{
if (start[i / 3, i % 3] != end[i / 3, i % 3])
{
return false;
}
}

return true;
}

/// <summary>
/// 检查是否超界和祖孙结点是否相同
/// </summary>
/// <param name="s"></param>
/// <param name="t"></param>
/// <returns></returns>
private bool CheckBorderAndFatherNode(int[] s, int[] t)
{
if (s[0] < 0 || s[0] > 2 || s[1] < 0 || s[1] > 2)
{
return false;
}
if (s[0] == t[0] && s[1] == t[1])
{
return false;
}

return true;
}

/// <summary>
/// 交换数据之间的数据
/// </summary>
/// <param name="a"></param>
/// <param name="s"></param>
/// <param name="t"></param>
/// <returns></returns>
public int[,] DataChange(int[,] a, int[] s, int[] t)
{
int temp = a[s[0], s[1]];
a[s[0], s[1]] = a[t[0], t[1]];
a[t[0], t[1]] = temp;
return a;
}

/// <summary>
/// 直接进行检查的入栈操作,不对其它进行操作
/// </summary>
/// <param name="s"></param>
/// <param name="p"></param>
/// <param name="depth"></param>
private void StackAdd(int[] s, int[] p, int depth, int[,] value)
{
//对四个方向进行判定,如果呼合要求的进行入栈的操作
//操作方向是上左下右四个方向顺序进行的
int[] svalue = new int[2];

lock (this)
{
svalue[0] = s[0] - 1;
svalue[1] = s[1];
//如果符合要求,就进行入栈的操作,在入栈的时候就进行对数据的一些记录操作
if (CheckBorderAndFatherNode(svalue, p))
{
DataCon dc = new DataCon();
dc.s = svalue;
dc.p = s;

dc.depth = depth;
dc.d = Direction.Up;
int[,] temp = value;
int[,] d = DataChange(temp, svalue, s);
dc.codevalue = d;//这里是记录和父结点交换后的排序

st.Push(dc);
}
}

lock (this)
{
svalue[0] = s[0];
svalue[1] = s[1] - 1;
if (CheckBorderAndFatherNode(svalue, p))
{
DataCon dc = new DataCon();
dc.s = svalue;
dc.p = s;

dc.depth = depth;
dc.d = Direction.Left;
int[,] temp = value;
int[,] d = DataChange(temp, svalue, s);
dc.codevalue = d;//这里是记录和父结点交换后的排序

st.Push(dc);
}
}

lock (this)
{
svalue[0] = s[0] + 1;
svalue[1] = s[1];
if (CheckBorderAndFatherNode(svalue, p))
{
DataCon dc = new DataCon();
dc.s = svalue;
dc.p = s;

dc.depth = depth;
dc.d = Direction.Down;
int[,] temp = value;
int[,] d = DataChange(temp, svalue, s);
dc.codevalue = d;//这里是记录和父结点交换后的排序

st.Push(dc);
}
}

lock (this)
{
svalue[0] = s[0];
svalue[1] = s[1] + 1;
if (CheckBorderAndFatherNode(svalue, p))
{
DataCon dc = new DataCon();
dc.s = svalue;
dc.p = s;

dc.depth = depth;
dc.d = Direction.Right;
int[,] temp = value;
int[,] d = DataChange(temp, svalue, s);
dc.codevalue = d;//这里是记录和父结点交换后的排序

st.Push(dc);
}
}
}



...全文
125 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
小曦子 2009-05-05
  • 打赏
  • 举报
回复
有没有人帮忙看一下我这里面出现的问题,谢谢啦
小曦子 2009-05-05
  • 打赏
  • 举报
回复
就没人帮忙进来瞧瞧吗,给点意见呀
小曦子 2009-05-05
  • 打赏
  • 举报
回复
int[,] d = DataChange(temp, svalue, s);
dc.codevalue = d;//这里是记录和父结点交换后的排序

public int[,] DataChange(int[,] a, int[] s, int[] t)
{
int temp = a[s[0], s[1]];
a[s[0], s[1]] = a[t[0], t[1]];
a[t[0], t[1]] = temp;
return a;
}





我通过断点查看到在数据交换完后返回给d时,也把其它全部的内容全部改变掉,变成入栈里面的每个内容都一样了,我一直想不通这是为什么,请各位给点意见!说说这是为什么
绿色夹克衫 2009-05-04
  • 打赏
  • 举报
回复
老帖子

http://topic.csdn.net/u/20090105/10/0ead37cf-93db-450f-9daa-aece8a6f6a17.html

[Quote=引用 8 楼 ytfsse 的回复:]
引用 6 楼 litaoye 的回复:
真的挺长的,比我以前写的双向搜的还要长呢!


哦,可否参考一下
[/Quote]
小曦子 2009-05-04
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 litaoye 的回复:]
真的挺长的,比我以前写的双向搜的还要长呢!
[/Quote]

哦,可否参考一下
小曦子 2009-05-04
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 Fibona 的回复:]
代码太长了,明天再看,

为什么当我改变了八数码里面的一个排列后,其它存储在未访问的栈里面的值也会改变了??

你用的是引用类型,所以会改变
[/Quote]
有点不懂,我明明已经放进栈里面了,什么还会改变里面的值呢,既然都最后一个入栈的一样
绿色夹克衫 2009-05-04
  • 打赏
  • 举报
回复
真的挺长的,比我以前写的双向搜的还要长呢!
Fibona 2009-05-04
  • 打赏
  • 举报
回复
代码太长了,明天再看,

为什么当我改变了八数码里面的一个排列后,其它存储在未访问的栈里面的值也会改变了??

你用的是引用类型,所以会改变
小曦子 2009-05-04
  • 打赏
  • 举报
回复
代码是有点长,可是只要全部复制里面的类到一个文件就可以执行的,我只是不明白,为什么当我改变了八数码里面的一个排列后,其它存储在未访问的栈里面的值也会改变了??
tommir3 2009-05-04
  • 打赏
  • 举报
回复
mark一下
小曦子 2009-05-04
  • 打赏
  • 举报
回复

/// <summary>
/// 定义数据结构,用来存储一些交换的相关数据
/// </summary>
public struct DataCon
{
public int[,] codevalue; //本身的状态
public int[] s; //当前被隐藏点的位置坐标
public int[] p; //自己父结点的坐标
public int depth; //当前自己的深度
public Direction d; //表示自己是从哪个方向走上来的
}

/// <summary>
/// 空格移动的方向
/// </summary>
public enum Direction
{
Down,
Up,
Left,
Right,
None
}

/// <summary>
/// 解答拼图是否存在
/// </summary>
public enum Answer
{
/// <summary>
/// 不存在解答
/// </summary>
NotExist,
/// <summary>
/// 存在解答
/// </summary>
Exist,
/// <summary>
/// 在当前指定的搜索深度内不存在解答(需要扩大深度)
/// </summary>
NotExistInDepth
}
struct P
{
public int value;
public int depth;
};


class Program
{
public Stack<P> s = new Stack<P>();





///*

int[] s = new int[2];
int[] p = new int[2];

int[,] start = new int[3, 3];
int[,] end = new int[3, 3];

p[0] = -1;
p[1] = -1;

s[0] = 1;
s[1] = 1;

for (int i = 0; i < 9; i++)
{
start[i / 3, i % 3] = i;
end[i / 3, i % 3] = i;
}

Random r = new Random();

for (int j = 0; j < 9; j++)
{
int p1 = r.Next(j);
int temp = start[j / 3, j % 3];
start[j / 3, j % 3] = start[(2 - p1 / 3), (2 - p1 % 3)];
start[(2 - p1 / 3), (2 - p1 % 3)] = temp;
}

AI ai = new AI();
Answer ans = ai.Compute(start, end, 30000, s, p, 0);
if (ans == Answer.NotExist)
{
Console.WriteLine("无解!");
//return;
Console.WriteLine("same: " + ai.same);
Console.WriteLine("time: " + ai.time);
Console.WriteLine("total: " + ai.total);
Console.WriteLine("count: " + ai.dict.Count);
Console.WriteLine("MaxDepth: " + ai.MaxDepth);
}

if (ans == Answer.NotExistInDepth)
{
Console.WriteLine("深度不够!");
//return;
Console.WriteLine("same: " + ai.same);
Console.WriteLine("time: " + ai.time);
Console.WriteLine("total: " + ai.total);
Console.WriteLine("count: " + ai.dict.Count);
Console.WriteLine("MaxDepth: " + ai.MaxDepth);
}

if (ans == Answer.Exist)
{
Console.WriteLine("恭喜你,已经解决了此问题!");
Console.WriteLine("same: " + ai.same);
Console.WriteLine("time: " + ai.time);
Console.WriteLine("total: " + ai.total);
Console.WriteLine("count: " + ai.dict.Count);
Console.WriteLine("MaxDepth: " + ai.MaxDepth);
}
//*/


System.Threading.Thread.Sleep(5000);
}
}



还要加上下面的些的
小曦子 2009-05-04
  • 打赏
  • 举报
回复
/// <summary>
/// 被隐藏的坐标,和它的父结点ss
/// </summary>
/// <param name="s"></param>
/// <param name="ps"></param>
/// <returns></returns>
private int DepthFirstSearch(int[] s, int[] p)
{
lock (this)
{
//在这里应该要入栈了,前面已经做过了第一次的所有结点的判断,这里直接入栈
DataCon dc = new DataCon();
dc.s = s;
dc.p = p;
depth++;
dc.depth = depth;//这里是第一次入栈,所有要加上1;
dc.d = Direction.None;//第一次入栈所有它所指的方向为无
dc.codevalue = start;//因为是第一次入栈,没有进行交换,只要把原始的状态加入就可以了

st.Push(dc);
//上面已经完成了所有第一步要操作的事务,下面就要开始判断后续的结点和入栈出栈的操作

//下面就要开始出栈的工作和判断周围四个方向的位置尔后再入栈
while (st.Count > 0)
{
DataCon dCon = (DataCon)st.Pop();
start = dCon.codevalue;
if (totalDir.ContainsValue(start))
{
same++;
}
else
{
totalDir.Add((totalDir.Count + 1), start);
}
//下面开始入栈工作和记录所走过的结点数和相同的数

//对于下面这个数还得进行一些深度的判断,如果深度大于它的,就进行加入,
//小于它的就对它本身体一些值进行删除,直到小于这个值,尔后再进行加入
if (dict.Count == 0)
{
dict.Push(dCon);
}
else
{
DataCon DataC = new DataCon();
DataC = (DataCon)dict.Pop();
if (dCon.depth > DataC.depth)
{
dict.Push(DataC);
dict.Push(dCon);
}
else
{
while (dict.Count != DataC.depth)
{
if (dict.Count == 0)
{
break;
}
DataC = (DataCon)dict.Pop();
}
dict.Push(dCon);
}
}
total++;

//下面
lock (this)
{
start = dCon.codevalue;
//判断是否已经完成所有的排序,如果完成则返回winnercode
if (IsSuccess(start, end))
{
return WinnerCode;
}

//排序没有成功,下面判断深度,对没有超界的再次进行入栈操作
//而且对四个方向入栈的深度是在父类的深度加1
if (dCon.depth < MaxDepth)
{
StackAdd(dCon.s, dCon.p, dCon.depth + 1, dCon.codevalue);
}
}
}

}

return -1;
}

private int BreadthFirstSearch()
{
return -1;
}

private int BestFirstSearch()
{
return -1;
}

/// <summary>
///
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="depth"></param>
/// <param name="s">初始坐标</param>
/// <param name="p">初始坐标的父结点</param>
/// <param name="mode"></param>
/// <returns></returns>
public Answer Compute(int[,] start, int[,] end, int depth, int[] s, int[] p, int mode)
{
//初始化一些数据
Init(start, end, depth);

//先检查是否有无解
if (ExistAns(start, end))
{
return Answer.NotExist;
}

//检查是事已经完成了排列
if (IsSuccess(start, end))
{
return Answer.Exist;
}

long oldtime = System.DateTime.Now.Ticks;//100 纳秒为间隔的间隔数
int eval = 0;
switch (mode)
{
case 0:
eval = DepthFirstSearch(s, p);
break;
case 1:
eval = BreadthFirstSearch();
break;
case 2:
eval = BestFirstSearch();
break;
default:
eval = BestFirstSearch();
break;
}
time = (System.DateTime.Now.Ticks - oldtime) / 10000000.0f;
if (eval == WinnerCode)
return Answer.Exist;

return Answer.NotExistInDepth;
}
}
}


我上面经过断点查询,发现最后出现的值都一样,我看了一下问题出现在private void StackAdd(int[] s, int[] p, int depth, int[,] value)
里面,为什么会出现这样的结果,请教一下各位前辈帮帮忙,上面是全部代码,是在控制台下执行的,请各位帮忙调试一下呀?谢谢

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧