Eight -- A*算法

http://acm.hdu.edu.cn/showproblem.php?pid=1043


今天又把八数码拿出来写了一遍,记得上次写这题是暑假集训的时候,那时POJ上能过,但是拿到HDU上交就TLE啊,只能说明POJ上,这题的数据太水了, ~~~  这次写主要也是为了学下A*算法吧。 不过我写的A* 在HDU上还是要1000+ms,囧。。 应该是启发函数没有处理好吧。。

算法:A* , BFS, IDA* 


BFS代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

#define MAX 363000

using namespace std;

char ch[30];
bool vis[MAX];
int d_r[4] = {1,-1,0,0} ;				//方向数组 
int d_c[4] = {0,0,1,-1} ;				
bool success ;
char path[4] = {'d','u','r','l'} ;		//方向数组
int fac[11] = {1,1,2,6,24,120,720,5040,40320,362880} ;
 
struct Node{
	int num[11];			//状态 
	int ka;					//该状态对应的KT值 
}start,goal;				//状态结构体 
queue<Node> q ;

struct Node2{
	int pre;			//状态(KT值唯一标示)的前一个状态 
	int way ;			//到达该状态的方式 
}state[MAX];

//求任意一个排列的KT展开 
inline int KT(int n,int num[])
{
	int i,j,t,sum=0 ;
	for(i=1;i<=n;i++)
	{
		t = 0 ;
		for(j=i+1;j<=n;j++)
			if(num[j] < num[i])	t++;		
		sum += t *fac[n-i] ;	
	} 
	return sum + 1 ;	
}


inline int recode(char s)
{
	if(s == 'x')	return 0;
	else	return s - '0' ;	
}

void find(int way,Node now)
{
	int num[5][5],i,j,t,pos_r,pos_c;
	Node a ;
	for(i=1;i<=3;i++)
	{
		for(j=1;j<=3;j++)
		{
			num[i][j] = now.num[(i-1)*3+j];
			if(num[i][j] == 9)
			{
				pos_r = i ; pos_c = j ;	
			}
		}	
	}	
	int new_r = pos_r + d_r[way] ;
	int new_c = pos_c + d_c[way] ;
	
	if(new_r>=1 && new_r<=3 && new_c>=1 && new_c<=3)
	{
		int temp = num[pos_r][pos_c] ;
		num[pos_r][pos_c] = num[new_r][new_c] ;
		num[new_r][new_c] = temp ;
		t= 1 ;
		for(i=1;i<=3;i++)
			for(j=1;j<=3;j++)
				a.num[t++] = num[i][j] ;		
		a.ka = KT(9,a.num);
		if(!vis[a.ka])
		{
			q.push(a);
			vis[a.ka] = true; 
			state[a.ka].pre = now.ka ;
			state[a.ka].way = way ;
			if(a.ka == goal.ka)
			{
				success = true ;	
			} 
		}				
	}
}

void PRINT(int ka)			//打印路径 
{
	int pre_ka = state[ka].pre ;
	if(pre_ka == -1)	return ;
	PRINT(pre_ka);
	printf("%c",path[state[ka].way]);		
}

int BFS(Node start)
{
	int i,j;
	Node now ;
	while(!q.empty())	q.pop();
	memset(vis,false ,sizeof(vis));
	vis[start.ka] = true;
	q.push(start);
	success = false ;
	state[start.ka].pre = -1 ;
	state[start.ka].way = 0 ;
	
	while(!q.empty())
	{
		now = q.front(); q.pop();
		for(i=0;i<4;i++)
		{
			find(i,now);
			if(success)
				break ;	
		}
		if(success)
			break;
	}
	if(success)
		PRINT(goal.ka);
	else
		printf("unsolvable\n");	
}

int main()
{
	int i,j,num,t,pos_x; 
    //freopen("1in.txt","r",stdin);
    //freopen("1out.txt","w",stdout);
    for(i=1;i<=9;i++)
    {
		goal.num[i] = i ;
	}
	goal.ka = 1 ;
   	while(gets(ch)!=NULL)
	{
		t = 1 ;
		for(i=0;ch[i]!=0;i++)
		{
			if(ch[i] == ' ')	continue ;
			start.num[t] = recode(ch[i]) ;
			if(start.num[t] == 0)
			{
				start.num[t] = 9 ; 	 	
			}
			t++ ;
		}
		start.ka = KT(9,start.num);
		BFS(start);			//广搜	
	}	
    return 0;
}


A*算法:这题严格来说不是用A*过的,而是用了一个is_ok()函数过的。。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cmath>

#define MAX 363000

using namespace std;

int d_r[4] = {0,0,-1,1} ;				//方向数组 
int d_c[4] = {1,-1,0,0} ;				
char path[4] = {'r','l','u','d'} ;		//方向数组
int fac[11] = {1,1,2,6,24,120,720,5040,40320,362880} ;
int d_x[10] = {0,1,1,1,2,2,2,3,3,3} ;
int d_y[10] = {0,1,2,3,1,2,3,1,2,3} ;
int vis[MAX] ;
char ans[MAX] ;

struct Node{
	int num[11];			//状态 
	int ka,space;			//该状态对应的KT值
	int h,g ; 
	friend  bool operator < (const Node & x,const Node & y)
	{
		return (x.h+x.g) > (y.h+y.g) ;
	}
}start,a,now;						//状态结构体 

priority_queue<Node> q ;

struct Node2{
	int pre;			//状态(KT值唯一标示)的前一个状态 
	int way ;			//到达该状态的方式 
}state[MAX];

//求任意一个排列的KT展开 
inline int KT(int n,int num[])
{
	int i,j,t,sum=0 ;
	for(i=1;i<=n;i++)
	{
		t = 0 ;
		for(j=i+1;j<=n;j++)
			if(num[j] < num[i])	t++;		
		sum += t * fac[n-i] ;	
	} 
	return sum  ;	
}

inline int cal_h(int num[])
{
	int h = 0;
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			int Num = num[(i-1)*3+j] ;
			h += abs(i - d_x[Num])+abs(j-d_y[Num]) ;		
		}	
	}
	return h;
}

inline void swap(int &a, int &b)
{
	int temp = a; a = b ; b = temp ;	
}

void PRINT(int ka)			//打印路径 
{
	int pre_ka = ka ,t=0;
	while(state[pre_ka].way != -1)
	{
		t++; 
		ans[t] = path[state[pre_ka].way] ;	
		pre_ka = state[pre_ka].pre ;
	}
	for(int j=t;j>=1;j--)
	{
		printf("%c",ans[j]);	
	}
	printf("\n");
}

void A_star(Node start)
{
	int i,j ,temp,pos_r,pos_c,new_r,new_c;
	start.ka = KT(9,start.num) ;
	start.g = 0 ;
	start.h = cal_h(start.num) ;
	while(!q.empty())	q.pop();
	memset(vis,0,sizeof(vis));	//0:未访问,1:已访问结点;  	
	vis[start.ka] = 1 ;
	q.push(start);
	state[start.ka].pre = -1 ;
	state[start.ka].way = -1 ;
	
	while(!q.empty())
	{
		now = q.top(); q.pop();
		if(now.ka == 0)
		{
			PRINT(0) ;
			return ;	
		}
		pos_r = (now.space-1)/3 + 1 ;
		pos_c = (now.space-1)%3 + 1 ;	
		
		for(i=0;i<4;i++)
		{
			temp = now.space ;
			new_r = pos_r + d_r[i] ;
			new_c = pos_c + d_c[i] ;
			a = now ;
			if(new_r<1 || new_r>3 || new_c<1 || new_c>3)	continue ;
			
			a.space = (new_r-1)*3 + new_c ;
			swap(a.num[a.space],a.num[temp]) ;
			a.ka = KT(9,a.num);
			if(vis[a.ka]==0)
			{
				a.g = now.g + 1 ;
				a.h = cal_h(a.num) ;
				q.push(a);
				vis[a.ka] = 1;
				state[a.ka].pre = now.ka ;
				state[a.ka].way = i ;
			}
		}			
	}
	
	printf("unsolvable\n");	
}

bool is_ok(int num[])
{
	int sum = 0 ;
	int num1[11] ,t=1;
	
	for(int i=1;i<=9;i++)
	{
		if(num[i]!=9)
		{
			num1[t++] = num[i] ;	
		}	
	}
	
	for(int i=1;i<=8;i++)
	{
		for(int j=1;j<i;j++)
		{
			if(num1[j]>num1[i])	sum++;
		}	
	}	
	if(sum%2==0)	return true;
	else	return false ;
}

int main()
{
	int i,j,num,t,pos_x; 
	char ch[5]; 
   	while(cin>>ch[1]>>ch[2]>>ch[3])
	{
		for(i=1;i<=3;i++)
		{
			if(ch[i] == 'x')
			{
				start.num[i] = 9 ;
				start.space = i;	
			}	
			else 
				start.num[i] = ch[i] - '0' ;
		}
		
		for(i=4;i<=9;i++)
		{
			cin>>ch[0] ;
			if(ch[0] == 'x')
			{
				start.num[i] = 9 ;
				start.space = i ;	
			}		
			else 
				start.num[i] = ch[0] - '0' ;
		}
		
		if(is_ok(start.num))
			A_star(start);			//广搜	
		else 
			printf("unsolvable\n");
	}	
    return 0;
}






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值