poj1198
poj1198:
Solitaire
Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.
There are four identical pieces on the board. In one move it is allowed to:
- move a piece to an empty neighboring field (up, down, left or right),
- jump over one neighboring piece to an empty field (up, down, left or right).
There are 4 moves allowed for each piece in the configuration shown above. As an example let's consider a piece placed in the row 4, column 4. It can be moved one row up, two rows down, one column left or two columns right.
Write a program that:
- reads two chessboard configurations from the standard input,
- verifies whether the second one is reachable from the first one in at most 8 moves,
- writes the result to the standard output.
用广度优先搜索求最小路径(其实原题给定了最大步数,深搜搜到第八步跳出循环也可以解决,但是容易超时)。
根据广度优先搜索的几个基本步骤,在写题之前先把思路整理好:
- 每个结点的棋盘都将只有四个点是棋子,也就是说,与其用8x8 的数组存储,不如只存坐标。
- 每个父结点的每个棋子都有4种走法,四个棋子有16种走法。如果搜到8步,那将是 16^8,也就是 2^32 = 429496729,数组开不下,并且必定会超时。
解决的办法有两个:
- 判重并且使用到哈希解码,对于冲突,我们可以用字符串记录路径,发生冲突时叠加字符串即可。对于判重,从头到尾的比较肯定会超时,我们可以开一个86878889长度的数组(可能出现的最大项,可以用平移优化),用来打标记判重。
- 我们可以写一个双向BFS(个人更喜欢这种做法),双向搜索只需要搜4层就够了。
值得注意的是,如果开数组打标记的方法判重,一定要把每个结点的四个坐标都排好序!
以下是代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
//定义棋子
struct point{
int x , y;
};
//定义初始、目标棋盘
point a[5] , b[5];
int numa , numb;
//输出棋盘
void print( point a[5] ){
for( int i = 1; i <= 4; ++i ) printf( "%d%d" , a[i].x , a[i].y );
printf( "\n" );
}
//将棋盘转换为十进制数
int f( point a[5] ){
int s = 0;
for( int i = 1; i <= 4; ++i ) s = s * 100 + a[i].x * 10 + a[i].y;
return s;
}
bool cmp( point a , point b ){
return a.x < b.x or ( a.x == b.x and a.y < b.y );
}
//偏移量
point d[5] = {{ 0 , 0 } ,
{ +1 , 0 } ,
{ -1 , 0 } ,
{ 0 , +1 } ,
{ 0 , -1 } };
//定义判重的数组 flag
bool flag[85868789];
//定义节点
struct node{
point a[5];
int dep;
int fa;
};
node data[6000000];
//判断x,y位置是否出界
bool check( int x , int y ){
return ( x >= 1 and x <= 8 and y >= 1 and y <= 8 );
}
//检查a棋盘的x,y位置是否有棋子 有返回真
bool check1( point a[5] , int x , int y ){
for( int i = 1; i <= 4; ++i )
if( a[i].x == x and a[i].y == y ) return true;
return false;
}
//复制棋盘
void copy1( point a[5] , point b[5] ){
for( int i = 1; i <= 4; ++i ) b[i].x = a[i].x , b[i].y = a[i].y;
}
int op , cl;
void print1( int cl ){
int ans[10] , n = 0;
while( cl != -1 ){
ans[++n] = cl;
cl = data[cl].fa;
}
printf( "\n\n" );
for( int i = n; i > 1; --i ) print( data[ans[i]].a );
print( data[ans[1]].a );
}
int main(){
//freopen("poj1198.in", "r", stdin);
for( int i = 1; i <= 4; ++i ) scanf( "%d%d" , &a[i].x , &a[i].y );
for( int i = 1; i <= 4; ++i ) scanf( "%d%d" , &b[i].x , &b[i].y );
//print(a);
//print(b);
sort( a + 1 , a + 5 , cmp );
sort( b + 1 , b + 5 , cmp );
numa = f( a );
numb = f( b );
//print(a);
//print(b);
//printf("%d %d\n", numa, numb);
//特判初始状态和目标状态
if( numa == numb ){
printf( "YES" );
return 0;
}
//初始化 首节点入队 首尾设置指针
copy1( a , data[1].a );
data[1].dep = 0;
data[1].fa = -1;
//memset(flag, false, sizeof flag);
flag[numa] = true;
op = 0 , cl = 1;
bool f1 = false;
while( op < cl and !f1 and data[op + 1].dep < 8 ){
++op;
int dep = data[op].dep;
for( int i = 1; i <= 4; ++i ){
for( int j = 1; j <= 4; ++j ){
copy1( data[op].a , a ); //每个操作要从原始棋盘开始
//x1,y1移动一步的位置
//x2,y2跳跃一步的位置
int x1 = a[i].x + d[j].x , y1 = a[i].y + d[j].y;
int x2 = x1 + d[j].x , y2 = y1 + d[j].y;
if( check( x1 , y1 ) and !check1( a , x1 , y1 ) ){ //x1,y1位置不出界且x1,y1位置无棋子
a[i].x = x1;
a[i].y = y1; //移动到新位置
sort( a + 1 , a + 5 , cmp ); //排序
numa = f( a ); //转化为数
if( !flag[numa] ){ //判重
flag[numa] = true; //标记
++cl; //入队
copy1( a , data[cl].a );
data[cl].dep = dep + 1;
data[cl].fa = op;
//判断目标
if( numa == numb ){
f1 = true;
break;
}
}
} else if( check( x1 , y1 ) and check( x2 , y2 ) and
check1( a , x1 , y1 ) and !check1( a , x2 , y2 ) ){
//x1,y1,x2,y2位置不出界且x1,y1位置有棋子,x2,y2位置无棋子
a[i].x = x2;
a[i].y = y2; //跳跃到新位置
sort( a + 1 , a + 5 , cmp ); //排序
numa = f( a ); //转化为数
if( !flag[numa] ){ //判重
flag[numa] = true; //标记
++cl; //入队
copy1( a , data[cl].a );
data[cl].dep = dep + 1;
data[cl].fa = op;
//判断目标
if( numa == numb ){
f1 = true;
break;
}
}
}
}
if( f1 ) break;
}
}
if( f1 ) printf( "YES\n" );
else
printf( "NO\n" );
return 0;
}


浙公网安备 33010602011771号