HDU 4634 Swipe Bo 状态压缩+BFS最短路
将起始点、终点和钥匙统一编号,预处理:
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最短路的更多相关文章
- hdu 4634 Swipe Bo bfs+状态压缩
题目链接 状态压缩记录当前拿到了哪些钥匙, 然后暴力搜索. 搞了好几个小时, 一开始也不知道哪里错了, 最后A了也不知道一开始哪里有问题. #include <iostream> #inc ...
- 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 ...
- hdu 4634 Swipe Bo 搜索
典型的bfs模拟 (广度优先搜索) ,不过有好多细节要注意,比如图中如果是 R# 走到这个R的话就无限往右走了,这样就挂了~肯定到不了出口.还有一种容易造成死循环的,比如 #E## DLLL D. ...
- hdu 3681 Prison Break(状态压缩+bfs)
Problem Description Rompire . Now it’s time to escape, but Micheal# needs an optimal plan and he con ...
- 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路
原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html 题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串 ...
- 胜利大逃亡(续)(状态压缩bfs)
胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu 4352 数位dp + 状态压缩
XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 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 ...
- 【HDU - 1429】胜利大逃亡(续) (高级搜索)【状态压缩+BFS】
Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)…… 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方.刚开 ...
随机推荐
- Noip2015总结
Noip2015战役总结 [游记部分] Day0 考前说是可以放松一下,下午呢就在机房打了几盘杀,一起玩了玩狼人.不过晚上觉得还是要有点氛围了,于是稍稍打了几个模板,觉得正确率还不错,给自己一点自信的 ...
- 快速幂取模 分类: ACM TYPE 2014-08-29 22:01 95人阅读 评论(0) 收藏
#include<stdio.h> #include<stdlib.h> //快速幂算法,数论二分 long long powermod(int a,int b, int c) ...
- Sprite Kit 入门教程
Sprite Kit 入门教程 Ray Wenderlich on September 30, 2013 Tweet 这篇文章还可以在这里找到 英语, 日语 If you're new here, ...
- rivers ioi2005 树形dp
说句实话,写完这道题,很想吐一口血出来,以示我心情的糟糕: 题目很简单,树形dp,正常做30分钟,硬是做了好几个小时,真是伤心. 题解不写了,只是吐个槽,网上没有用背包写的dp,全是左儿子右兄弟写法, ...
- centos 安装软件
1)一种是软件的源代码,您需要自己动手编译它.这种软件安装包通常是用gzip压缩过的tar包(后缀为.tar.gz).2)另一种是软件的可执行程序,你只要安装它就可以了.这种软件安装包通常被是一个RP ...
- mysql if条件
#if表达式 SELECT reg_no, IF(reg_no='718170554','黄色宾利','红色宾利') FROM car WHERE reg_no IN ('718170554','12 ...
- 用linux服务器下的/dev/shm/来释放磁盘的压力
巧用linux服务器下的/dev/shm/来释放磁盘的压力 浏览:646 | 更新:2013-06-18 18:08 | 标签: 磁盘 tmpfs是Linux/Unix系统上的一种基于内存的文件系统. ...
- POJ 1001 Exponentiation(JAVA,BigDecimal->String)
题目 计算实数a的n次方,具体输出格式看案例 import java.util.*; import java.math.*; public class Main { public static voi ...
- iOS验证码倒计时(GCD实现)
+ (void)verificationCode:(void(^)())blockYes blockNo:(void(^)(id time))blockNo { __block ; //倒计时时间 d ...
- .Net知识点总结(一)
1.文件上传:Jquery.uploadify 它依赖于flash 舍去起上传 功能 改用SWFupload 他是第三方的插件 2.验证码激活的时候,邮箱开始是写死的,但是为了以后更改邮箱 ...