推门游戏 The Wall Pushers(IDA*)

这个题的大致意思:是说你可以推一面墙,但是不能推两面墙,而且也不能推墙推过边界,问你最少要多少步才能走出迷宫。

这题的迷宫规模较小,好像可以搜索,但是直接搜又好像太慢了,所以可以用(IDA*)进行搜索。

关于估价函数的话,显然,最少也是要走到边界才能够走出迷宫,所以估价函数就是棋子走到边界的最近值。

由于在路途中可能会有障碍(指推不动的墙),所以估价函数一定是小于等于准确值的,正确性得到保证。

在搜索中用二进制来记录和更改墙的位置,例如1111代表四周都有墙。

就像这样:

int value(int x,int y)
{
	return min(x-1,min(6-x,min(y-1,4-y)));
}

(IDA*)除了估价函数的构建,其他也就是一个搜索了,应该大家都会,就不在多讲。

说几个坑点:

1.题目中所给的数据的输入方式是反的,所以输入的时候要x,y反着输入

2.墙后有墙不能够推墙。

3.推了一个墙,有三个格子的墙会改变:

在这里插入图片描述
例如,最左边的格子的右墙被推了之后,中间格子的左墙就没有了,中间格子会多一个右墙,最右边的格子会多一个左墙,所以说有很多的地方需要更改。

4.走出去的那一步也要计算进路径中。

5.走的方向也有先后顺序:西北东南

#include<bits/stdc++.h>
using namespace std;
int a[7][7],minn,f[4][2]={{-1,0},{0,-1},{1,0},{0,1}},tx,ty;
bool flag;
char ch[200],dir[4]={'W','N','E','S'};
int value(int x,int y)//估价函数
{
	return min(x-1,min(6-x,min(y-1,4-y)));
}
bool check(int x,int y)
{
	if((x==1&&(!(a[x][y]&1)))||(x==6&&(!(a[x][y]&4)))||(y==1&&(!(a[x][y]&2)))||(y==4&&(!(a[x][y]&8))))
	{
		return 1;
	}
	return 0;
}
void dfs(int x,int y,int step,int last)//IDA*
{
	if(step+value(x,y)>minn||flag)
	{
		return;
	}
	if(check(x,y))//最后一步
	{
		flag=1;
		if(x==1&&(!(a[x][y]&1)))
		{
			ch[step]='W';
		}
		if(x==6&&(!(a[x][y]&4)))
		{
			ch[step]='E';
		}
		if(y==1&&(!(a[x][y]&2)))
		{
			ch[step]='N';
		}
		if(y==4&&(!(a[x][y]&8)))
		{
			ch[step]='S';
		}
		cout<<ch<<endl;
		return;
	}
	for(int i=0;i<4;i++)
	{
		int xx=x+f[i][0],yy=y+f[i][1],xxx=xx+f[i][0],yyy=yy+f[i][1];
		if(xx<1||xx>6||yy<1||yy>4||abs(last-i)==2||((a[x][y]&(1<<i))&&(a[xx][yy]&(1<<i))))
		{
			continue;
		}
		if(a[x][y]&(1<<i))//有墙且可以推
		{
			a[x][y]-=(1<<i);
			a[xx][yy]+=(1<<i)-(1<<((i+2)%4));
			a[xxx][yyy]+=(1<<((i+2)%4));
			ch[step]=dir[i];
			dfs(xx,yy,step+1,i);
			if(flag)
			{
				return;
			}
			ch[step]=0;
			a[x][y]+=(1<<i);
			a[xx][yy]-=(1<<i)-(1<<((i+2)%4));
			a[xxx][yyy]-=(1<<((i+2)%4));
		}else{
			ch[step]=dir[i];//无墙
			dfs(xx,yy,step+1,i);
			if(flag)
			{
				return;
			}
			ch[step]=0;
		}
	}
}
int main()
{
	while(scanf("%d%d",&tx,&ty)&&(tx||ty))
	{
		flag=0;
		for(int i=1;i<=4;i++)//反着输入
		{
			for(int j=1;j<=6;j++)
			{
				scanf("%d",&a[j][i]);
			}
		}
		for(minn=1;;minn++)
		{
			memset(ch,0,sizeof(ch));
			dfs(tx,ty,0,44);
			if(flag)
			{
				break;
			}
		}
	}
	return 0;
}
/*
3 1
5 2 6 12 6 9 
14 2 7 2 10 14 
8 4 12 4 4 8 
12 6 6 14 4 12 
0 0
*/
原文地址:https://www.cnblogs.com/2017gdgzoi44/p/12196259.html