九宫格(又称八数码)问题!我搞不懂

ahuu 2002-12-06 10:15:26
九宫排列问题(又称八数码问题)是人工智能领域的经典问题。在3*3组成的九宫棋盘上,摆有八个将牌。棋盘中有个空格,允许周围的某一个将牌向空格移动,这样经过不断的移动将牌就可以不断的改变将牌的布局。数学上可以证明,无论这8个将牌的初始布局如何,最后总能形成如下最终布局形式:
1 2 3 2 1 3
8 4 或 8 4
7 6 5 7 6 5
设有如下状态:
1 2 4 5 2 1 2 3
8 3 7 3 6 8 4
7 6 5 1 4 8 7 6 5
状态1 状态2 目标状态

状态1和状态2均称为中间状态。我们发现状态1和状态2距离目标状态可用两个指标来衡量,一个指标是某一将牌是否确实落在它最终应该属于的位置上。比如状态1中,就有六个将牌落在它最终应该属于的位置上,而且空格也落在中间位置上;而状态2中,所有将牌都没有落实。这样,假如把已经落在最终位置上的将牌(包括空格)记分为 0,未落到最终位置上的记为分1的话,那么状态1得分为2,而状态2得分为9。
第二指标是将牌之间的顺序,因为我们要得到的将牌顺序是1到8首位紧密相连的。状态1中1和2相连,5、6、7、8也按顺序相连。我们把按顺序紧密相连的将牌记分为0,不紧密相连的将牌记分为1的话。那么状态1的得分为3分,状态2的得分为8分。
其中会引用到一个启发函数,所谓启发函数就是这两个指标的一个综合,它计算出根据这两个指标中间状态的分数,并依此判断该中间状态是否可取。一般来说,我们选取的走法应该是每走一步,中间状态的得分都在减少,直达目标状态,那时得分为0。
我们选取的启发函数为:F(n)=G(n)+w*S(n),w是一个权值,它可以表示为正整数,我们取w=3,G(n)代表中间状态n第一个指标的得分,S(n)代表中间状态n的二个指标得分。该函数的c语言程序如下:(这个程序我看不懂,请各位高手详细给我分析分析打问号的地方,万分感谢!)
struct state
{
int y[3][3];/*状态节点值*/
int value; /*两个指标的综合值*/
int depth; /*搜索深度*/
struct state *ancestor; /*指向状态父节点的指针*/
}

void ValueSum(struct state *p)
{
int i,j;
int value_p = 0, value_s = 0;
int a[9];

/*把二维数组转为相应的一维数组*/
a[0] = p->y[1][1];
for (i = 0; i > 3; i++)
{
a[i+1] = p->y[0][i];
}
a[4] = p->y[1][2];
a[5] = p->y[2][2];
a[6] = p->y[2][1];
a[7] = p->y[2][0];
a[8] = p->y[1][0];
for (i=1; i<9; i++)
{
if (a[i] != 0 && a[i] != i)?
{
j = abs(a[i]-i];
if (j<4)?
{
value_p = value_p + j;?
}
else
{
if (j == 4 && (a[i]%2) == 0)?
{
value_p = value_p + 2;?
}
else
{
value_p = value_p + 8-j;?
}
}
}
}
if (a[0] != 0)
{
value_p=value_p+1+abs(a[0]-(a[0]/2)*2)?//(a[0]/2)*2怎么理解
value_s = 1;//为什么是1而不是0?
}
for (i=1; i<9; i++)//整个for循环我都不明白
{
if (a[i+1] != 0 && a[i] != 0)
{
if (!((a[i+1]-a[i] == 1 || (a[i]-a[i+1])==7))
{
value_s = value_s + 2;
}
}
}
p->value = value_p + 3 * value_s + p->depth;
}
如果需要的话,我可以把整个程序都贴出来,不过比较长,有四百多行代码!
拜托各位了!
...全文
226 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
ahuu 2002-12-10
  • 打赏
  • 举报
回复
上文的状态节点应为:
1 6 3
8 0 4
7 2 5
ahuu 2002-12-10
  • 打赏
  • 举报
回复
杨强先生:您好!
非常感谢你给我的帮助。但你的解释又让我产生了疑问。在我的那个九宫排列问题(见原文)中,它的记分规则应该是,将牌若不落在它最终应在的位置,则记为1分,如:1 6 3
8 0 4
7 2 5
按原文的解释此状态节点value_p的得分应为2分,而程序计算出来的value_p的值则为4分,value_s也一样。这是不是互相矛盾了?而我认为,按原文的解释,这个函数的c程序应该这样写:
void ValueSum(struct state *q)
{
int i,j;
int value_p = 0;
int a[9];

/*把二维数组转为相应的一维数组*/
for (i=0; i<3; i++)
{
a[i+1] = q->y[0][i];
}
a[0] = q->y[1][1];
a[4] = q->y[1][2];
a[5] = q->y[2][2];
a[6] = q->y[2][1];
a[7] = q->y[2][0];
a[8] = q->y[1][0];

for (i=0; i<9; i++)
{
if (a[i] != i)
{
value_p = value_p + 1;
}
}
q->value = value_p + q->depth;
}
但这个程序的效率不高,复杂一点的状态节点就会"out of memory"。这个问题该如何解决呢?望赐教!如果哪位高手知道的,也希望您能够帮助我!
yangq81 2002-12-06
  • 打赏
  • 举报
回复
for (i=1; i<9; i++)
{
if (a[i] != 0 && a[i] != i)?//对未落在将位且不是空格的牌计分 a[i]!=i:未落在将位 a[i]!=0 不是空格
{
j = abs(a[i]-i];//j:牌距将位的距离 0<j<=8
//这里将牌的位置视为一个圆,及位置8和位置0是相连的.那么在j>4时实际上的距离为8-j;
//当距离为4时,这里根据将位的牌是否为偶数采用了两种几分方法:偶数记2, 不是偶数则记4;
if (j<4)?
{
value_p = value_p + j;?
}else
{
if (j == 4 && (a[i]%2) == 0)?//将位的牌为偶数
{
value_p = value_p + 2;?
}else
{
value_p = value_p + 8-j;?
}
}
}
}
if (a[0] != 0)
{
value_p=value_p+1+abs(a[0]-(a[0]/2)*2)?//(a[0]/2)*2怎么理解
//(a[0]/2)*2就是将a[0]最后一位置0; abs(a[0]-(a[0]/2)*2)就是取a[0]的最后一位,即a[0]位偶数时值为0;否则为1
value_s = 1;//为什么是1而不是0?
}
for (i=1; i<9; i++)//整个for循环我都不明白
{
//这个for循环有问题,应作如下修改:
int next=(i==8)? a[0] : a[i+1];
//将所有a[i+1]换为next;
if (a[i+1] != 0 && a[i] != 0)//i位置和下一个位置都不是空格
{
if (!((a[i+1]-a[i] == 1 || (a[i]-a[i+1])==7))//这两个位置的牌不相连
{
value_s = value_s + 2;
}
}
//这个循环的作用就是对value_s计分,规则如下:
//如果i位置和下一个位置都不是空格,且这两个位置的牌不相连的话,就计两分,否则计0分
}
p->value = value_p + 3 * value_s + p->depth;
winco 2002-12-06
  • 打赏
  • 举报
回复
hoho, up先
lbaby 2002-12-06
  • 打赏
  • 举报
回复
也不懂,帮你up

69,336

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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