8 数码问题

#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。根据棋盘距离来作为比较,并且用有序链表保存,提高速度 。

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值