将起始点、终点和钥匙统一编号,预处理:

1.起始点到所有钥匙+终点的最短路

2.所有钥匙之间两两的最短路

3.所有钥匙到终点的最短路

将起始点和所有钥匙四方向出发设为起点BFS一遍,求出它到任意点任意方向的最短路dp[i][j][k]。(即到点(i,j)且方向为k的最短路),BFS时需要注意:

1.UDLR有可能组成死循环

2.转向符在墙边并且指向了墙时,无法重新选择方向。例如这个: S...L#E

3.只有豆腐块滑动碰到墙停止了之后,才能把这个点的坐标加入队列。在滑动过程中经过的点都不需要加入队列。

4.钥匙在墙边的情况。在一次滑动过程中,豆腐块经过K时只有一个方向。但是如果K在墙边,并且滑动方向可以使豆腐块在K的位置停住,那么在这个K的位置,豆腐块向四方向移动的状态都是可达的。

例如:S.....E......K#

在我的方法中,如果不特殊处理的话,会出现经过K时,只有向右的状态是可达的,其它方向都不可达。但是实际上,从K开始向上下左右的状态显然都是合法状态,都可以达到。

5.遇到强制转向符号的时候step是不会增加的,只有在墙边停止下来重新选择方向的时候step才+1

KtoK[i][j][x][y]表示起始点为 i 方向为x到终点为j方向为y的最短路

用二进制表示得到钥匙的状态,一共7把钥匙,2^7种状态。

ans[x][y][z]表示得到钥匙的状态为x,经过的最后一把钥匙为y且此时方向为z的最短路。

ans[x][y][z] = min( ans[ x ^ ( 1 << y ) ][ k ][ m ] + KtoK[k][y][m][z] );

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std; const int MAXN = ;
const int INF = << ;
const int dx[] = { -, , , };//上下左右
const int dy[] = { , , -, }; struct Point
{
int x, y;
int move; //最小步数
int toward; //当前朝向
bool st;
Point( int x = , int y = , int mv = , int ct = , int to = , bool st = false ):
x(x), y(y), move(mv), toward(to), st(st) { }
}; int R, C;
int dp[MAXN][MAXN][];
int KtoK[][][][]; //钥匙i到钥匙j起始方向为x终止方向为y的最短路
int ans[ << ][][];
char mat[MAXN][MAXN];
int cntK; //钥匙个数
Point start, end, Key[]; void init()
{
for ( int i = ; i < ; ++i )
for ( int j = ; j < ; ++j )
for ( int m = ; m < ; ++m )
for ( int n = ; n < ; ++n )
KtoK[i][j][m][n] = INF; cntK = ;
for ( int i = ; i <= R; ++i )
for ( int j = ; j <= C; ++j )
{
switch ( mat[i][j] )
{
case 'S':
start.x = i, start.y = j;
break;
case 'E':
end.x = i, end.y = j;
break;
case 'K':
Key[cntK].x = i, Key[cntK].y = j, ++cntK;
break;
}
} Key[] = start;
Key[cntK] = end;
return;
} bool check( int x, int y )
{
return x > && x <= R && y > && y <= C;
} int BFS( Point st )
{
//printf("st(%d, %d)to%d ed(%d, %d)to%d\n", st.x, st.y, st.toward, ed.x, ed.y, ed.toward );
for ( int i = ; i < MAXN; ++i )
for ( int j = ; j < MAXN; ++j )
for ( int k = ; k < ; ++k )
dp[i][j][k] = INF;
dp[ st.x ][ st.y ][ st.toward ] = ; queue<Point> Q;
Q.push(st); while ( !Q.empty() )
{
Point p = Q.front();
Q.pop();
//printf("====%d %d\n", p.x, p.y ); int len = p.st ? p.toward : ;
for ( int i = p.st ? p.toward : ; i <= len; ++i )
{
int xx = p.x, yy = p.y;
if ( !check( xx + dx[i], yy + dy[i] ) ) continue;
if ( mat[ xx + dx[i] ][ yy + dy[i] ] == '#' ) continue; bool ok = true;
int toward = i;
while ( mat[xx][yy] != '#' )
{
//printf("%d %d %d\n", xx, yy, p.st );
switch( mat[xx][yy] )
{
case 'U':
toward = ;
break;
case 'D':
toward = ;
break;
case 'L':
toward = ;
break;
case 'R':
toward = ;
break;
default:
break;
}
xx += dx[toward];
yy += dy[toward];
if ( !check( xx, yy ) )
{
ok = false;
break;
}
int &res = dp[xx][yy][toward];
//printf( "%d dp[%d][%d][%d]=%d, %d\n", ok, xx, yy, toward, res, p.move + 1 );
if ( ok && p.move < res )
{
res = p.move;
if ( check( xx + dx[toward], yy + dy[toward] ) )
{
if ( mat[ xx + dx[toward] ][ yy + dy[toward] ] == '#' )
{
if ( mat[xx][yy] != 'L' && mat[xx][yy] != 'R' && mat[xx][yy] != 'U' && mat[xx][yy] != 'D' )
{
if ( mat[xx][yy] == 'K' ) //特殊处理K在墙边的情况
{
for ( int k = ; k < ; ++k )
dp[xx][yy][k] = min( dp[xx][yy][k], p.move + );
}
Q.push( Point( xx, yy, p.move + , , false ) );
}
}
}
}
else break; //之前少了这句话,一直TLE
}
}
}
return INF;
} int main()
{
//freopen("1006.in","r",stdin);
//freopen("out.txt","w",stdout);
while ( ~scanf( "%d%d", &R, &C ) )
{
for ( int i = ; i <= R; ++i )
scanf( "%s", &mat[i][] ); init(); //预处理所有钥匙之间的最短路
for ( int i = ; i < cntK; ++i )
{
for ( int k = ; k < ; ++k )
{
Point st = Key[i];
st.move = ;
st.st = true;
st.toward = k;
BFS( st );
for ( int j = ; j <= cntK; ++j )
for ( int m = ; m < ; ++m )
{
if ( i == j && k == m )
{
KtoK[i][j][k][m] = ;
continue;
}
KtoK[i][j][k][m] = dp[ Key[j].x ][ Key[j].y ][m];
//printf( "KtoK[%d][%d][%d][%d] = %d\n", i, j, k, m, KtoK[i][j][k][m] );
}
}
} for ( int i = ; i < ( << ( cntK - ) ); ++i )
for ( int j = ; j < cntK; ++j )
for ( int k = ; k < ; ++k ) ans[i][j][k] = INF; for ( int i = ; i < ; ++i ) ans[][][i] = ; for ( int i = ; i < ( << ( cntK - ) ); ++i )
for ( int j = ; j < cntK; ++j )
for ( int k = ; k < ; ++k )
{
int v = ans[i][j][k];
if ( v == INF ) continue;
for ( int y = ; y < cntK; ++y )
for ( int z = ; z < ; ++z )
{
int x = ( i | ( << ( y - ) ) );
if ( ans[x][y][z] > v + KtoK[j][y][k][z] )
ans[x][y][z] = v + KtoK[j][y][k][z];
}
} int aa = INF;
for ( int i = ; i < cntK; ++i )
for ( int j = ; j < ; ++j )
for ( int k = ; k < ; ++k )
{
aa = min( aa, ans[ ( << ( cntK - ) ) - ][i][j] + KtoK[i][cntK][j][k] );
}
if ( aa >= INF ) aa = -;
printf( "%d\n", aa );
}
return ;
}

HDU 4634 Swipe Bo 状态压缩+BFS最短路的更多相关文章

  1. hdu 4634 Swipe Bo bfs+状态压缩

    题目链接 状态压缩记录当前拿到了哪些钥匙, 然后暴力搜索. 搞了好几个小时, 一开始也不知道哪里错了, 最后A了也不知道一开始哪里有问题. #include <iostream> #inc ...

  2. HDU 4634 Swipe Bo (2013多校4 1003 搜索)

    Swipe Bo Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  3. hdu 4634 Swipe Bo 搜索

    典型的bfs模拟 (广度优先搜索) ,不过有好多细节要注意,比如图中如果是  R#  走到这个R的话就无限往右走了,这样就挂了~肯定到不了出口.还有一种容易造成死循环的,比如 #E## DLLL D. ...

  4. hdu 3681 Prison Break(状态压缩+bfs)

    Problem Description Rompire . Now it’s time to escape, but Micheal# needs an optimal plan and he con ...

  5. 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html 题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串 ...

  6. 胜利大逃亡(续)(状态压缩bfs)

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  7. hdu 4352 数位dp + 状态压缩

    XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  8. HDU 5025 Saving Tang Monk 【状态压缩BFS】

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=5025 Saving Tang Monk Time Limit: 2000/1000 MS (Java/O ...

  9. 【HDU - 1429】胜利大逃亡(续) (高级搜索)【状态压缩+BFS】

    Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)…… 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方.刚开 ...

随机推荐

  1. 常见的百度蜘蛛IP

    根据不同的IP我们可以分析网站是个怎样的状态, 以下常见的百度蜘蛛IP: 123.125.68.*这个蜘蛛经常来,别的来的少,表示网站可能要进入沙盒了,或被者降权. 220.181.68.*每天这个I ...

  2. 对git认识

    Github则是一个基于Git的日益流行的开源项目托管库.它的使用流程不需要联机,可以先将对代码的修改,评论,保存在本机.等上网之后,再实时推送过去.同时它创建分支与合并分支更容易,推送速度也更快,配 ...

  3. 01.Redis安装

    1.安装Redis 1.下载.解压Redis [lizhiwei@localhost Redis]$ ll total 1248 -rwxrwxr-x. 1 lizhiwei lizhiwei 127 ...

  4. ELF文件格式

    ELF--Linux下可执行文件格式   1.类型          常见的ELF格式文件包括:                                                     ...

  5. Matlab实现单变量线性回归

    一.理论 二.数据集 6.1101,17.592 5.5277,9.1302 8.5186,13.662 7.0032,11.854 5.8598,6.8233 8.3829,11.886 7.476 ...

  6. Nginx使用webbench进行压力测试(转载)

    在运维工作中,压力测试是一项非常重要的工作.比如在一个网站上线之前,能承受多大访问量.在大访问量情况下性能怎样,这些数据指标好坏将会直接影响用户体验. 但是,在压力测试中存在一个共性,那就是压力测试的 ...

  7. HTTP状态码一览表(HTTP Status Code)

    copy from:http://www.189works.com/article-43064-1.html 1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明 100 ( ...

  8. 数据库表 copy

    db1为原数据库,db2为要导出到的数据库,fromtable 是要导出的表名 1.方法一:登录导出到的数据库,执行create table fromtable select * from db1.f ...

  9. ftp命令和scp命令

    ftp命令: 服务器有安装ftp Server,另外一台linux可以使用ftp的client程序来进行文件的拷贝读取和下载. 1. 连接ftp服务器  格式:ftp [hostname| ip-ad ...

  10. vuforia 结合 unity3d 开发 AR 的 androidAPP 总结

    原地址:https://software.intel.com/zh-cn/blogs/2014/07/09/vuforia-unity3d-ar-androidapp/?utm_campaign=CS ...