IDA*算法

http://poj.org/problem?id=1077


/*
procedure dfs(depth:longint);
 begin
  if 要剪枝 then exit;
  if 可行 then Print;
  if Depth<MaxDepth then dfs(depth+1);
 end;

procedure Iterative_Deepening;
 begin
  MaxDepth:=0;
  while true do
   begin
    inc(MaxDepth);
    dfs(1);
   end;
 end;
*/

#include <iostream> 
#include <math.h> 
using namespace std; 
struct Status 
{ 
	int board[3][3]; 
	int px,py; 
}; 
Status init,target={1,2,3,4,5,6,7,8,9,2,2}; 
int targetPos[10][2],path[10000],maxDepth; 
int move[4][2]={0,-1,-1,0,0,1,1,0}; 

/*
*奇偶剪枝
*每移动一次X方块,必定需要移动一次另外的方块
*所以其他方块需要移动的次数+X方块移动的次数必定是偶数
*/
bool IsSolvable() 
{ 
	int i,j,k=0,sum=0,array[9]; 
	for(i=0; i!=3; ++i) 
		for(j=0; j!=3; ++j) 
			array[k++] = init.board[i][j]; 
	//除了X结点外,要到达目标位置需要移动的最大步数,因为在转换成了一维后原本可以上下移动的都被转化成了水平移动.
	//但是幸运的是,他们是同奇同偶的.具体的证明我也不知道,画图有这么个规律
	for(i = 0; i != 8; ++i) 
		for(j = i + 1; j != 9; ++j) 
			if(array[i] > array[j]) 
				sum++; 
	//这个是X方块到目标位置的最短步数,不管怎么移动,只要最后是在目标位置,必定是同奇同偶的.(简单的考虑就是撤销)
	//而每一次的其他方块的移动都是与X方块的交换来实现的,所以他们的和必定是偶数
	sum += abs(init.px - targetPos[9][0]) + abs(init.py - targetPos[9][1]); 	
	return sum % 2 == 0; 
}

// heuristic function 
//计算该状态需要移动的距离
int H(Status &s)         
{ 
	int sum=0, tmp; 
	for(int i = 0; i != 3; ++i) 
		for(int j = 0; j != 3; ++j) 
		{ 
			tmp = s.board[i][j]; 
			if(tmp < 9) 
				sum += abs(i - targetPos[tmp][0]) + abs(j-targetPos[tmp][1]); 
		} 
	return sum; 
} 

void Output(int depth) 
{
	for(int i=0; i < depth; ++i) 
		if(path[i] == 0) 
			cout<<'l'; 
		else if(path[i] == 1) 
			cout<<'u'; 
		else if(path[i] == 2) 
			cout<<'r'; 
		else cout<<'d'; 
} 

bool IDAStar(Status &s, int depth, int h, int prev) 
{ 
	if(memcmp(&s, &target, sizeof(Status)) == 0) 
	{
		Output(depth); 
		return true; 
	} 
	if(depth >= maxDepth) 
		return false; 
	Status ns; int nh,nx,ny,tmp;  //next status 
	for(int k = 0; k != 4; ++k) 
	{ 
		//这里会撤销上一步的移动,跳过
		if(abs(k - prev) == 2) 
			continue; 
		ns = s; 
		nx = s.px + move[k][0]; 
		ny = s.py + move[k][1]; 
		//越界
		if(nx < 0 || ny < 0 || nx == 3 || ny == 3) 
			continue; 
		//移动操作
		tmp = s.board[nx][ny]; 
		ns.board[s.px][s.py] = tmp; 
		ns.board[nx][ny] = 9; 
		ns.px = nx; ns.py = ny; 
		//向上移动,并且x在与他交换的方块的目标位置的上方,也就是说,与他交换的方块理目标位置近了一步
		//可能在上方也可能就是那个位置了
		if(k == 0 && ny < targetPos[tmp][1]) 
			nh = h - 1;   // l 
		else if(k == 1 && nx < targetPos[tmp][0]) 
			nh = h - 1;  // u 
		else if(k == 2 && ny > targetPos[tmp][1]) 
			nh = h - 1;  // r 
		else if(k == 3 && ny < targetPos[tmp][0]) 
			nh = h - 1;  // d 
		else 
			nh = h + 1; //走歪路了.
		//不是合法结点.h(n) + g(n) > f(n)..
		if(depth + nh >= maxDepth) 
			continue; 
		path[depth] = k; 
		if(IDAStar(ns, depth+1, nh, k)) 
			return true; 
	} 
	return false; 
}

int main() 
{ 
	char tmp; int index=0; 
	for(int i = 0; i != 3; ++i) 
		for(int j = 0; j != 3; ++j) 
		{ 
			cin>>tmp; 
			if(tmp == 'x') 
			{ 
				tmp = '9'; 
				init.px = i; 
				init.py = j; 
			} 
			init.board[i][j] = tmp - '0'; 
			targetPos[++index][0] = i; 
			targetPos[index][1] = j; 
		} 
	if(IsSolvable()) 
	{ 
		int h = H(init); 
		//迭代加深,搜索深度作为限制,这个算法还不是很了解..迭代加深..
		for(maxDepth = h; ; maxDepth++) 
			if(IDAStar(init, 0, h, -10)) 
				break;         
	} 
	else 
		cout<<"unsolvable"; 
	return 0; 
} 


posted @ 2011-01-16 02:13  Cranny  阅读(2223)  评论(0编辑  收藏  举报