#include "stdio.h"
#include "math.h"
#include "malloc.h"
int des[3][3]={{0,1,2},{3,4,5},{6,7,8}};//标准
struct Node
{
int src[3][3];
int i;
int j;
int sum;
Node *next;
};
Node *head,*closed;//一个做OPEN表,一个做CLOSE表
int deep=0;//设置深度,防止无限调用
int d(int src[][3],int des[3][3])//算出棋盘距离
{
int i,j,mod,chu,sum=0;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
chu=abs(src[i][j]-des[i][j])/3;
mod=abs(src[i][j]-des[i][j])%3;
sum+=chu+mod;
}
}
return sum;
}
void addClose( Node * closed, Node * head ) //加入CLOSE表
{
Node *q,*temp;//临时替代head
temp=(Node*)malloc(sizeof(Node));
temp->i=head->i;
temp->j=head->j;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
temp->src[i][j]=head->src[i][j];
temp->sum=head->sum;
temp->next=NULL;
q=closed;
while(q!=NULL&&q->next!=NULL)
{
q=q->next;
}
if(q==NULL)
{
q=temp;
closed=q;
}
else
q->next=temp;
return;
}
int Isclose( Node * closed, Node *p ) //属于CLOSE表不?是返回0,不是返回1
{
Node *q;
q=closed;
while(q!=NULL)
{
if(d(q->src,p->src)==0)
return 0;
q=q->next;
}
return 1;
}
void link(Node *x,Node *y)//将y节点插入到以X为头节点的链表中
{
Node *p,*q;
p=x;
if(y->sum<p->sum)//开始插入比第一个小
{
y->next=x;
head=y;
return;
}
else
{
while(p->next!=NULL&&p->sum<y->sum)
{
p=p->next;
}
if(p->next==NULL)
{
p->next=y;
y->next=NULL;
head=x;
return;
}
if(p->sum==y->sum)
{
while(p->next!=NULL&&p->sum==y->sum)
{
if(d(p->src,y->src)==0)
return;
q=p;
p=p->next;
}
if(p->next==NULL)
{
q->next=y;
y->next=NULL;
}
else
{
y->next=q->next;
q->next=y;
}
}
head=x;
}
}
int Canslove(Node *suc,int (*goal)[3])//逆序数比较求解
{
int suma=0,sumb=0,i,j,a[9],b[9];
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
a[i*3+j]=suc->src[i][j];
b[i*3+j]=goal[i][j];
}
for(i=1;i<9;i++)
for(j=0;j<i;j++)
{
if(a[i]<a[j]&&a[i]!=0)
suma++;
if(b[i]<b[j]&&b[i]!=0)
sumb++;
}
printf("%d %d",suma,sumb);
if(suma%2==sumb%2)//统计逆序数的总个数
return 1;
else
return 0;
}
void eight(int src[3][3],int srci,int srcj)//8数码
{
int i,j,temp,deep=0;
Node srcnode,*p,*q,*z;
closed=(Node*)malloc(sizeof(Node));
closed->next=NULL;
srcnode.i=srci;
srcnode.j=srcj;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
srcnode.src[i][j]=src[i][j];
srcnode.sum=d(src,des);
if(!Canslove(&srcnode,des))
{
printf("找不到");
return;
}
srcnode.next=NULL;
z=&srcnode;
while (z->sum!=0)
{
if(z->i+1<3)//下
{
q=(Node*)malloc(sizeof(Node));
q=z;
p=(Node*)malloc(sizeof(Node));
p->i=q->i+1;
p->j=q->j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
p->src[i][j]=q->src[i][j];
temp=p->src[p->i][p->j];
p->src[p->i][p->j]=p->src[p->i-1][p->j];
p->src[p->i-1][p->j]=temp;//交换数据
p->sum=d(p->src,des);
if(Isclose(closed,p))
{
link(q,p);
}
}
if(z->i-1>=0)//上
{
q=(Node*)malloc(sizeof(Node));
q=z;
p=(Node*)malloc(sizeof(Node));
p->i=q->i-1;
p->j=q->j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
p->src[i][j]=q->src[i][j];
temp=p->src[p->i][p->j];
p->src[p->i][p->j]=p->src[p->i+1][p->j];
p->src[p->i+1][p->j]=temp;//交换数据
p->sum=d(p->src,des);
if(Isclose(closed,p))
{
link(q,p);
}
}
if(z->j+1<3)//右
{
q=(Node*)malloc(sizeof(Node));
q=z;
p=(Node*)malloc(sizeof(Node));
p->i=q->i;
p->j=q->j+1;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
p->src[i][j]=q->src[i][j];
temp=p->src[p->i][p->j];
p->src[p->i][p->j]=p->src[p->i][p->j-1];
p->src[p->i][p->j-1]=temp;//交换数据
p->sum=d(p->src,des);
if(Isclose(closed,p))
{
link(q,p);
}
}
if(z->j-1>=0)//左
{
q=(Node*)malloc(sizeof(Node));
q=z;
p=(Node*)malloc(sizeof(Node));
p->i=q->i;
p->j=q->j-1;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
p->src[i][j]=q->src[i][j];
temp=p->src[p->i][p->j];
p->src[p->i][p->j]=p->src[p->i][p->j+1];
p->src[p->i][p->j+1]=temp;//交换数据
p->sum=d(p->src,des);
if(Isclose(closed,p))
{
link(q,p);
}
}
if(deep==2)//防止无限深度调用
{
//printf("超过\n");
addClose(closed,head);
/*查出closed表中的个数
Node *m;
int l=0;
m=head;
while(m->next!=NULL)
{
l++;
m=m->next;
}
printf("%d\n",l);
l=0;
*/
head=head->next;
if(head==NULL)//open表被用完
{
printf(" 找不到\n");
return ;
}
deep=0;
}
if(z==head)
deep++;
z=head;
//输出变化
// for(i=0;i<3;i++)
// {
// for(j=0;j<3;j++)
// {
// printf("%d ",head->src[i][j]);
// }
// printf("\n");
// }
// printf("\n");
}
printf("找到了\n");
}
void main()
{
int i,j,src[3][3],srci,srcj;
printf("请输入8数码的源数据:\n");
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
scanf("%d",&src[i][j]);
if(src[i][j]==0)
{
srci=i;
srcj=j;
}
}
}
printf("\n");
eight(src,srci,srcj);
}
1.非递归实现8数码,利用逆序数进行先验计算可计算性。具体函数Canslove()。
2。利用COLSED表和OPEN表,保存使用过和没使用过的节点。
3。根据棋盘距离来作为比较,并且用有序链表保存,提高速度 。