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

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. Java实现文件压缩与解压[zip格式,gzip格式]

    Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例. zip扮演着归档和压缩两个角色:gzip并 ...

  2. 我是一只it小小鸟阅读笔记

    “我们具有各自的独特性--我们兴趣各异,有不同的家庭背景,不同的知识储备,不同的思维方式……但在现实中,我们也会碰到类似的人生选择的关口,我们会犯类似的错误,有类似的迷惘,也会为类似的精彩鼓掌,而且很 ...

  3. bzoj 2761 平衡树

    裸地平衡树,只需要用到find操作 /**************************************************************     Problem:     U ...

  4. 【BZOJ】【3504】【CQOI2014】危桥

    网络流/最大流 比较裸的最大流= = 无向图上走来回其实就等价与走两遍>_> 如果路径有相交其实不影响答案的 比较恶心的是两个人路过同一座桥,但走的方向不同互相抵消流量了…… 其实只要在第 ...

  5. vsm 的理解

    vsm相对于最原始的sm多了这样一个部分 if(depthcampare <=zInSM) fPercentLit  = 1;//noshadow; else { variance = zzIn ...

  6. Cross Validation done wrong

    Cross Validation done wrong Cross validation is an essential tool in statistical learning 1 to estim ...

  7. UML 2.0(装载)

    在世界上统一建模语言UML2.0是完全不同的维度.它在本质上更加复杂和广泛. 与UML1.5版本相比,文件的程度也增加了. UML2.0中还增加了新的功能,所以它的使用可以更广泛. UML2.0将正式 ...

  8. ASP.NET制作一个简单的等待窗口

    前一阵做一个项目,在处理报表的时候时间偏长,客户提出要做出一个等待窗口提示用户等待(页面太久没反映,用户还以为死了呢).在分析这一需求之后,觉得如果要实现像winform应用中的processbar太 ...

  9. 关于linux系统如何实现fork的研究(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 前一篇关于linux系统如何实现fork的研究(一)通过代码已经说明了从用户态怎么通过软中断实现调用系统调 ...

  10. Java 并发同步器之CountDownLatch、CyclicBarrier

    一.简介 1.CountDownLatch是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时,await()方法会阻塞 ...