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

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. 【Populating Next Right Pointers in Each Node II】cpp

    题目: Follow up for problem "Populating Next Right Pointers in Each Node". What if the given ...

  2. IOS常用加密DES

    NSString+DES.h // // NSString+DES.h // haochang // // Created by Administrator on 14-4-15. // Copyri ...

  3. maven插件:tomcat插件和jetty插件的区别

    在程序是多模块结构的时候,使用tomcat的maven插件和jetty的maven插件有细微差别: 1.tomcat7-maven-plugin   可以直接在parent的邮件直接运行:tomcat ...

  4. 【BZOJ】【1211】【HNOI2004】树的计数

    Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明 ...

  5. Matlab验证公式取值范围

    一.问题来源 t = 2xy/(x+y);融合相似度和信任度,我需要验证值域是不是[0,1]: 二.求解 clear all; clc; %linspace(0:1,0.1)这样是错的,第三个参数是段 ...

  6. JAVA 显示图片的简单源码 分类: Java Game 2014-08-14 10:10 77人阅读 评论(0) 收藏

    此代码的原理就是用JLabel来加载图片,再将JLabel放入JFrame中, package com.mywork; import javax.swing.ImageIcon; import jav ...

  7. HDAO one error

    对normal target设置的background clearcolor 导致 远处天空 通过了 normalRejectTest 所以要对normal target单独设置 不能通过test的 ...

  8. PS4 Razor GPU

    这东西,从出来就感觉没用,各种请教也都没有帮助.虽然搞明白了 rt啊tex啊buffer啊但是就是感觉对于抓bug没有用处.所以从来都是像巫师一样靠直觉,再用科学的方法来测试,其实就是让ps retu ...

  9. vector存入共享内存(了解)

    昨天在上篇blog里描写了如何把STL容器放到共享内存里去,不过由于好久不写blog,发觉词汇组织能力差了很多,不少想写的东西写的很零散,今天刚好翻看自己的书签,看到一篇挺老的文章,不过从共享内存到S ...

  10. phonegap上传以及下载图片

    在phonegap中,有时我们需要从服务器下载图片以及上传图片,这个时候可以用到官方提供的一个插件:FileTransfer 首先通过命令添加插件: cordova plugin add org.ap ...