ZJU 3531 Alice Madness Return 【BFS HASH状态】
有一段日子木有更新solution神马的,北京区域赛的准备工作好烦哪。强烈要求出现一个组委会,而不是我们这帮集训队的来干各种奇葩活。言归正传,9月的浙大月赛可搞题颇多,场上就想写这题,可惜木有机时,只能场下写咯。可惜一写就掉坑里了,直到现在才爬出来,好恶心的一道题啊。
题意:
10*10的棋盘,有一个你控制的棋子A,每步可四向移动;有一个镜像棋子B,和你呈镜像运动,遇边、石则当前回合不动;路上有石头,不可入;有压路机,循环运动,遇神杀神,遇石回头;地图上有<=5个宝石,你需要用A去拾取全部(WA点1,用A拾取,B没用);有两个出口,需要让A、B同时到达这俩出口,且拿满宝石,则你赢了。被压路机压到A、B或者同时到达出口时宝石没拿满,都是死。
做法:
就是BFS+模拟,模拟的规则略复杂。
先说状态,压路机方向 + 压路机位置 + A位置 + B位置 + 五块宝石的拿取状态。最后一个状态我用2^5来存,所以整体是一个9位数(虽说大牛们说前两个状态因为压路机的循环移动性质乘起来只有20种)。整体状态数=2 * 10 * 100 * 100 * 32 = 6400000 ,果断hash。一开始用MAP,TLE了;后来只能手写hash了,不仅要记hash之前的状态值还需要记对应状态的权值,难怪那么大内存。
接着就是模拟了:
每次解hash(注意hash数字时候的顺序)得取当前状态,然后算出下一回合A、B、压路机K的位置和宝石状态。
但是判定非法的时候,需要按顺序判断:
因为走的顺序是A、B、K,所以先判断A,check(超范围、碰R),碰K(未动),碰B,碰到则状态非法;再判断B,若碰新A,check,碰K,则不动。先不判K。
然后判断A是否拿到了新的宝石。
此时要判断A、B是否达到了出口,如果达到了而宝石不齐,则状态非法(wa点2);若齐了,则更新最短路长(不要在出队以后再更新,要在入队前更新,否则压路机会把这种情况给判非法掉)。只要达到出口,则状态不进队。
最后判K,吃了A或者B则状态非法。(WA点3)
代码写的好矬啊,别人800ms过,我wa+tle了两版才2400ms过。。。蒟蒻伤不起啊。
#include
<
iostream
>
#include < cstdio >
#include < cstring >
#include < map >
#include < queue >
#include < algorithm >
using namespace std;
#define maxn 11
#define hashsize (6400013)
#define maxm (hashsize + 10)
int ans;
const int inf = 1 << 30 ;
char mst[maxn][maxn];
int vis[maxm];
int cas;
int tot;
struct HASH
{
int x,step;
HASH(){}
HASH( int _x, int _s):x(_x),step(_s){}
}h[maxm];
inline int find( int x)
{
int z = x % hashsize;
return vis[z] == cas ? h[z].step: - 1 ;
}
inline void insert( int x, int value)
{
int z = x % hashsize;
vis[z] = cas;
h[z] = HASH(x,value);
}
inline void update( int x, int value)
{
int z = x % hashsize;
h[z].step = value;
}
struct node
{
int x,y;
node(){}
node( int a, int b):x(a),y(b){}
bool operator == ( const node p)
{
return x == p.x && y == p.y;
}
}pa,pb,en[ 2 ],ki,pc[ 6 ];
int r,c;
int pcs;
char dir;
int dx[] = { - 1 , 1 , 0 , 0 };
int dy[] = { 0 , 0 , - 1 , 1 };
char rd[] = { ' N ' , ' S ' , ' W ' , ' E ' };
int co( char _d)
{
for ( int i = 0 ;i < 4 ;i ++ )
if (rd[i] == _d)
return i;
}
int hash( int _d,node p[], bool gd[])
{
int x = 0 ;
for ( int i = 0 ;i < pcs;i ++ )
if (gd[i])
x |= ( 1 << i);
int idx = 100 ;
for ( int i = 2 ;i >= 0 ;i -- )
{
x += idx * p[i].x;
idx *= 10 ;
x += idx * p[i].y;
idx *= 10 ;
}
x += (_d + 1 ) * idx;
return x;
}
inline bool check( int x, int y)
{
return 0 <= x && x < r && 0 <= y && y < c && mst[x][y] != ' R ' ;
}
void bfs()
{
queue < int > Q;
bool gd[ 6 ];
for ( int i = 0 ;i < pcs;i ++ )
gd[i] = true ;
node p[ 3 ];
p[ 0 ] = ki;
p[ 1 ] = pa;
p[ 2 ] = pb;
int s = hash(co(dir),p,gd);
// cout << s << endl;
if (find(s) == - 1 )
insert(s, 0 );
Q.push(s);
// cout << s << endl;
while ( ! Q.empty())
{
int now = Q.front();
Q.pop();
// cout << now << endl;
int step = find(now);
int idx = 100000000 ;
int tdir = now / idx - 1 ;
now -= (tdir + 1 ) * idx;
idx /= 10 ;
// cout << now << endl;
for ( int i = 0 ;i < 3 ;i ++ )
{
p[i].y = now / idx;
now -= p[i].y * idx;
idx /= 10 ;
p[i].x = now / idx;
now -= p[i].x * idx;
idx /= 10 ;
}
// cout << now << endl;
int x,y;
x = p[ 0 ].x + dx[tdir];
y = p[ 0 ].y + dy[tdir];
if ( ! check(x,y))
{
x = p[ 0 ].x;
y = p[ 0 ].y;
tdir ^= 1 ;
}
node tk = node(x,y);
for ( int i = 0 ;i < 4 ;i ++ )
{
bool dg[ 6 ] = { 0 };
int ax = p[ 1 ].x + dx[i],ay = p[ 1 ].y + dy[i];
int bx = p[ 2 ].x + dx[i ^ 1 ],by = p[ 2 ].y + dy[i ^ 1 ];
if ( ! check(ax,ay) || node(ax,ay) == p[ 0 ] || node(ax,ay) == p[ 2 ]) // they can stay in the same point???
continue ;
if ( ! check(bx,by) || node(bx,by) == p[ 0 ] || node(bx,by) == node(ax,ay))
{
bx = p[ 2 ].x;
by = p[ 2 ].y;
}
int what = 0 ;
for ( int j = 0 ;j < pcs;j ++ )
if (((now >> j) & 1 ) && ! (node(ax,ay) == pc[j]))
{
dg[j] = 1 ;
what |= 1 << j;
}
node q[ 3 ];
q[ 0 ] = tk;
q[ 1 ] = node(ax,ay);
q[ 2 ] = node(bx,by);
int ano = step + 1 ;
if ((en[ 0 ] == q[ 1 ] && en[ 1 ] == q[ 2 ]) || (en[ 0 ] == q[ 2 ] && en[ 1 ] == q[ 1 ]))
{
if (what == 0 )
ans = min(ano,ans);
else
continue ;
}
if (q[ 0 ] == q[ 1 ] || q[ 0 ] == q[ 2 ])
continue ;
int temp = hash(tdir,q,dg);
int comp = find(temp);
if (comp == - 1 || comp > ano)
{
if (comp == - 1 )
insert(temp,ano);
else
update(temp,ano);
Q.push(temp);
}
}
}
printf( " %d\n " ,ans == inf ?- 1 :ans);
}
int main()
{
cas = 0 ;
while (scanf( " %d %d " , & r, & c) == 2 )
{
cas ++ ;
int end = 0 ;
pcs = 0 ;
tot = 0 ;
for ( int i = 0 ;i < r;i ++ )
for ( int j = 0 ;j < c;j ++ )
{
char opt;
scanf( " %c " , & opt);
mst[i][j] = opt;
switch (opt)
{
case ' A ' :
pa = node(i,j);
break ;
case ' B ' :
pb = node(i,j);
break ;
case ' K ' :
ki = node(i,j);
break ;
case ' E ' :
en[end ++ ] = node(i,j);
break ;
case ' M ' :
pc[pcs ++ ] = node(i,j);
break ;
}
}
ans = inf;
scanf( " %c " , & dir);
bfs();
}
}
#include < cstdio >
#include < cstring >
#include < map >
#include < queue >
#include < algorithm >
using namespace std;
#define maxn 11
#define hashsize (6400013)
#define maxm (hashsize + 10)
int ans;
const int inf = 1 << 30 ;
char mst[maxn][maxn];
int vis[maxm];
int cas;
int tot;
struct HASH
{
int x,step;
HASH(){}
HASH( int _x, int _s):x(_x),step(_s){}
}h[maxm];
inline int find( int x)
{
int z = x % hashsize;
return vis[z] == cas ? h[z].step: - 1 ;
}
inline void insert( int x, int value)
{
int z = x % hashsize;
vis[z] = cas;
h[z] = HASH(x,value);
}
inline void update( int x, int value)
{
int z = x % hashsize;
h[z].step = value;
}
struct node
{
int x,y;
node(){}
node( int a, int b):x(a),y(b){}
bool operator == ( const node p)
{
return x == p.x && y == p.y;
}
}pa,pb,en[ 2 ],ki,pc[ 6 ];
int r,c;
int pcs;
char dir;
int dx[] = { - 1 , 1 , 0 , 0 };
int dy[] = { 0 , 0 , - 1 , 1 };
char rd[] = { ' N ' , ' S ' , ' W ' , ' E ' };
int co( char _d)
{
for ( int i = 0 ;i < 4 ;i ++ )
if (rd[i] == _d)
return i;
}
int hash( int _d,node p[], bool gd[])
{
int x = 0 ;
for ( int i = 0 ;i < pcs;i ++ )
if (gd[i])
x |= ( 1 << i);
int idx = 100 ;
for ( int i = 2 ;i >= 0 ;i -- )
{
x += idx * p[i].x;
idx *= 10 ;
x += idx * p[i].y;
idx *= 10 ;
}
x += (_d + 1 ) * idx;
return x;
}
inline bool check( int x, int y)
{
return 0 <= x && x < r && 0 <= y && y < c && mst[x][y] != ' R ' ;
}
void bfs()
{
queue < int > Q;
bool gd[ 6 ];
for ( int i = 0 ;i < pcs;i ++ )
gd[i] = true ;
node p[ 3 ];
p[ 0 ] = ki;
p[ 1 ] = pa;
p[ 2 ] = pb;
int s = hash(co(dir),p,gd);
// cout << s << endl;
if (find(s) == - 1 )
insert(s, 0 );
Q.push(s);
// cout << s << endl;
while ( ! Q.empty())
{
int now = Q.front();
Q.pop();
// cout << now << endl;
int step = find(now);
int idx = 100000000 ;
int tdir = now / idx - 1 ;
now -= (tdir + 1 ) * idx;
idx /= 10 ;
// cout << now << endl;
for ( int i = 0 ;i < 3 ;i ++ )
{
p[i].y = now / idx;
now -= p[i].y * idx;
idx /= 10 ;
p[i].x = now / idx;
now -= p[i].x * idx;
idx /= 10 ;
}
// cout << now << endl;
int x,y;
x = p[ 0 ].x + dx[tdir];
y = p[ 0 ].y + dy[tdir];
if ( ! check(x,y))
{
x = p[ 0 ].x;
y = p[ 0 ].y;
tdir ^= 1 ;
}
node tk = node(x,y);
for ( int i = 0 ;i < 4 ;i ++ )
{
bool dg[ 6 ] = { 0 };
int ax = p[ 1 ].x + dx[i],ay = p[ 1 ].y + dy[i];
int bx = p[ 2 ].x + dx[i ^ 1 ],by = p[ 2 ].y + dy[i ^ 1 ];
if ( ! check(ax,ay) || node(ax,ay) == p[ 0 ] || node(ax,ay) == p[ 2 ]) // they can stay in the same point???
continue ;
if ( ! check(bx,by) || node(bx,by) == p[ 0 ] || node(bx,by) == node(ax,ay))
{
bx = p[ 2 ].x;
by = p[ 2 ].y;
}
int what = 0 ;
for ( int j = 0 ;j < pcs;j ++ )
if (((now >> j) & 1 ) && ! (node(ax,ay) == pc[j]))
{
dg[j] = 1 ;
what |= 1 << j;
}
node q[ 3 ];
q[ 0 ] = tk;
q[ 1 ] = node(ax,ay);
q[ 2 ] = node(bx,by);
int ano = step + 1 ;
if ((en[ 0 ] == q[ 1 ] && en[ 1 ] == q[ 2 ]) || (en[ 0 ] == q[ 2 ] && en[ 1 ] == q[ 1 ]))
{
if (what == 0 )
ans = min(ano,ans);
else
continue ;
}
if (q[ 0 ] == q[ 1 ] || q[ 0 ] == q[ 2 ])
continue ;
int temp = hash(tdir,q,dg);
int comp = find(temp);
if (comp == - 1 || comp > ano)
{
if (comp == - 1 )
insert(temp,ano);
else
update(temp,ano);
Q.push(temp);
}
}
}
printf( " %d\n " ,ans == inf ?- 1 :ans);
}
int main()
{
cas = 0 ;
while (scanf( " %d %d " , & r, & c) == 2 )
{
cas ++ ;
int end = 0 ;
pcs = 0 ;
tot = 0 ;
for ( int i = 0 ;i < r;i ++ )
for ( int j = 0 ;j < c;j ++ )
{
char opt;
scanf( " %c " , & opt);
mst[i][j] = opt;
switch (opt)
{
case ' A ' :
pa = node(i,j);
break ;
case ' B ' :
pb = node(i,j);
break ;
case ' K ' :
ki = node(i,j);
break ;
case ' E ' :
en[end ++ ] = node(i,j);
break ;
case ' M ' :
pc[pcs ++ ] = node(i,j);
break ;
}
}
ans = inf;
scanf( " %c " , & dir);
bfs();
}
}
å
backward sentence