Problem UVA1601-The Morning after Halloween

Accept: 289 Submit: 3136

Time Limit: 12000 mSec

 Problem Description

 Input

 Output

For each dataset in the input, one line containing the smallest number of steps to restore ghosts into the positions where they are supposed to be should be output. An output line should not contain extra characters such as spaces.

 Sample Input

 

 Sample Ouput

7

36

77

题解:双向BFS经典题目。

抛开双向BFS,这个题的预处理也很值得学习。节点个数太多16*16=256,并且有三个鬼,所以状态总数几乎是256^3,不管是时间还是空间,肯定都要炸,所以就要把状态算的精确一些,省去一些不可能的情况,首先最外层都是'#',这样这个图就变成了最大14*14 = 196,还是有点大,注意题目条件,每2*2中至少有一个障碍,所以这196个点至多有75%是空格,196*0.75 = 147。这就差不多了,由于后面可能有加点的操作,不过最多加2个点,也就是说总数不会超过150,这个数字就比较理想了,时间上和空间上都不错。判重的问题,刚才分析过了,每个鬼能够出现的格子数目不超过150,八位二进制数就能表示,因此三个就可以用24位二进制数表示,和int还有一段距离,所以转换成一个int型整数判重是再好不过的了。将所有空格连接起来用的是类似邻接表的操作,不过lrj没有用vector,可能还是效率原因吧。

之后就是双向BFS的模板了,两个队列,分别入队出发点和终点,vis数组肯定是三维的,只是原来的0、1变成了现在的0、1、2,因为要区分是在哪一边扩展的过程中遍历到的这个点。当一个点在两个队列中都出现了,就说明找到了,返回dis的和,别忘了+1.还有一个需要注意的是双向BFS每次扩展一层而不是扩展一个节点。原因参考下面的链接:

http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx

先来一个单向BFS,680ms

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std; const int maxs = ;
const int maxn = ; int n,m,cnt,sum;
int deg[maxn],G[maxn][maxn];
int x[maxn],y[maxn],id[maxn][maxn];
int d[maxn][maxn][maxn];
int s[],t[];
int dx[] = {,,,-,};
int dy[] = {,,-,,}; int find_ID(int a,int b,int c){
return (a<<)|(b<<)|c;
} bool conflict(int a,int b,int a2,int b2){
if((a2==b && a==b2) || a2==b2) return true;
return false;
} int bfs(){
queue<int> que;
d[s[]][s[]][s[]] = ;
que.push(find_ID(s[],s[],s[]));
while(!que.empty()){
int top = que.front();que.pop();
int a = (top>>)&0xff,b = (top>>)&0xff,c = (top&0xff);
if(a==t[] && b==t[] && c==t[]) return d[a][b][c];
for(int i = ;i < deg[a];i++){
int a2 = G[a][i];
for(int j = ;j < deg[b];j++){
int b2 = G[b][j];
if(conflict(a,b,a2,b2)) continue;
for(int k = ;k < deg[c];k++){
int c2 = G[c][k];
if(d[a2][b2][c2] != -) continue;
if(conflict(a,c,a2,c2)) continue;
if(conflict(b,c,b2,c2)) continue;
d[a2][b2][c2] = d[a][b][c]+;
que.push(find_ID(a2,b2,c2));
}
}
}
}
return -;
} int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(~scanf("%d%d%d\n",&m,&n,&sum) && (m||n||sum)){
char gra[maxs][maxs];
cnt = ;
memset(d,-,sizeof(d));
for(int i = ;i < n;i++) fgets(gra[i],maxs,stdin); for(int i = ;i < n;i++){
for(int j = ;j < m;j++){
if(gra[i][j] != '#'){
x[cnt] = i,y[cnt] = j,id[i][j] = cnt;
if(islower(gra[i][j])) s[gra[i][j]-'a'] = cnt;
else if(isupper(gra[i][j])) t[gra[i][j]-'A'] = cnt;
cnt++;
}
}
} for(int i = ;i < cnt;i++){
int X = x[i],Y = y[i];
deg[i] = ;
for(int k = ;k < ;k++){
int xx = X+dx[k],yy = Y+dy[k];
if(gra[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
}
} if(sum <= ){
s[] = t[] = G[cnt][] = cnt;
deg[cnt++] = ;
}
if(sum <= ){
s[] = t[] = G[cnt][] = cnt;
deg[cnt++] = ;
} printf("%d\n",bfs());
}
return ;
}

再来一个双向BFS,530ms

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std; const int maxs = ;
const int maxn = ; int n,m,cnt,sum;
int deg[maxn],G[maxn][maxn];
int x[maxn],y[maxn],id[maxn][maxn];
int d[maxn][maxn][maxn];
int vis[maxn][maxn][maxn];
int s[],t[];
int dx[] = {,,,-,};
int dy[] = {,,-,,}; int find_ID(int a,int b,int c){
return (a<<)|(b<<)|c;
} bool conflict(int a,int b,int a2,int b2){
if((a2==b && a==b2) || a2==b2) return true;
return false;
} int bfs(){
queue<int> que,anti_que;
d[s[]][s[]][s[]] = ;
d[t[]][t[]][t[]] = ; que.push(find_ID(s[],s[],s[]));
anti_que.push(find_ID(t[],t[],t[])); vis[s[]][s[]][s[]] = ;
vis[t[]][t[]][t[]] = ; while(!que.empty() && !anti_que.empty()){
int num = que.size(),anti_num = anti_que.size();
while(num--){
int top = que.front();que.pop();
int a = (top>>)&0xff,b = (top>>)&0xff,c = (top&0xff); for(int i = ;i < deg[a];i++){
int a2 = G[a][i];
for(int j = ;j < deg[b];j++){
int b2 = G[b][j];
if(conflict(a,b,a2,b2)) continue;
for(int k = ;k < deg[c];k++){
int c2 = G[c][k];
if(conflict(a,c,a2,c2)) continue;
if(conflict(b,c,b2,c2)) continue; if(vis[a2][b2][c2] == ){
d[a2][b2][c2] = d[a][b][c]+;
vis[a2][b2][c2] = ;
que.push(find_ID(a2,b2,c2));
}
else if(vis[a2][b2][c2] == ){
return d[a][b][c]+d[a2][b2][c2]+;
}
}
}
}
} while(anti_num--){
int top = anti_que.front();anti_que.pop();
int a = (top>>)&0xff,b = (top>>)&0xff,c = (top&0xff); for(int i = ;i < deg[a];i++){
int a2 = G[a][i];
for(int j = ;j < deg[b];j++){
int b2 = G[b][j];
if(conflict(a,b,a2,b2)) continue;
for(int k = ;k < deg[c];k++){
int c2 = G[c][k];
if(conflict(a,c,a2,c2)) continue;
if(conflict(b,c,b2,c2)) continue; if(vis[a2][b2][c2] == ){
d[a2][b2][c2] = d[a][b][c]+;
vis[a2][b2][c2] = ;
anti_que.push(find_ID(a2,b2,c2));
}
else if(vis[a2][b2][c2] == ){
return d[a][b][c]+d[a2][b2][c2]+;
}
}
}
}
}
}
return -;
} int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(~scanf("%d%d%d\n",&m,&n,&sum) && (m||n||sum)){
char gra[maxs][maxs];
cnt = ;
memset(d,-,sizeof(d));
memset(vis,,sizeof(vis));
for(int i = ;i < n;i++) fgets(gra[i],maxs,stdin); for(int i = ;i < n;i++){
for(int j = ;j < m;j++){
if(gra[i][j] != '#'){
x[cnt] = i,y[cnt] = j,id[i][j] = cnt;
if(islower(gra[i][j])) s[gra[i][j]-'a'] = cnt;
else if(isupper(gra[i][j])) t[gra[i][j]-'A'] = cnt;
cnt++;
}
}
} for(int i = ;i < cnt;i++){
int X = x[i],Y = y[i];
deg[i] = ;
for(int k = ;k < ;k++){
int xx = X+dx[k],yy = Y+dy[k];
if(gra[xx][yy] != '#') G[i][deg[i]++] = id[xx][yy];
}
} if(sum <= ){
s[] = t[] = G[cnt][] = cnt;
deg[cnt++] = ;
}
if(sum <= ){
s[] = t[] = G[cnt][] = cnt;
deg[cnt++] = ;
} printf("%d\n",bfs());
}
return ;
}

UVA1601-The Morning after Halloween(双向BFS)的更多相关文章

  1. UVa1601 - The Morning after Halloween [单向bfs]

    解题思路: 1.注意到2*2方格中必有一个#,那么最多只有192条通道,可以将所有非‘#’的位置提取出来用邻接表的方式建图,通过bfs搜索目标位置. 2.将三个ghost的位置(a,b,c)作为状态量 ...

  2. UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS && 降维 && 状压)

    题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...

  3. UVA-1601 The Morning after Halloween(BFS或双向BFS)

    题目大意:在一张图中,以最少的步数将a,b,c移到对应的A,B,C上去.其中,每个2x2的方格都有障碍并且不能两个小写字母同时占据一个格子. 题目分析:为避免超时,先将图中所有能联通的空格建起一张图, ...

  4. 【UVa】1601 The Morning after Halloween(双向bfs)

    题目 题目     分析 双向bfs,对着书打的,我还调了好久.     代码 #include<cstdio> #include<cstring> #include<c ...

  5. UVA - 1601 The Morning after Halloween (双向BFS&单向BFS)

    题目: w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...

  6. POJ1915Knight Moves(单向BFS + 双向BFS)

    题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...

  7. HDU 3085 Nightmare II 双向bfs 难度:2

    http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...

  8. POJ 3170 Knights of Ni (暴力,双向BFS)

    题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...

  9. [转] 搜索之双向BFS

    转自:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx 如果目标也已知的话,用双向BFS能很大程度上提高速度. 单向时,是 b^le ...

随机推荐

  1. 1. volatale 关键字 -内存可见性

    package com.gf.demo01; /** * 一.volatile 关键字:但多个线程进行操作共享数据时,可以保证内存中数据可见性. * */ public class TestVolat ...

  2. Unix awk的流程控制BEGIN和END的讲解

    你可能对Unix比较熟悉,但你可能对Unix awk很陌生,这一点也不奇怪,的确,与其优秀的功能相比,awk还远没达到它应有的知名度. 流程控制语句是任何程序设计语言都不能缺少的部分.任何好的语言都有 ...

  3. Mybatis框架基础支持层——反射工具箱之Reflector&ReflectorFactory(3)

    说明:Reflector是Mybatis反射工具的基础,每个Reflector对应一个类,在Reflector中封装有该类的元信息, 以及基于类信息的一系列反射应用封装API public class ...

  4. Java并发编程-CountDownLatch

    基于AQS的前世今生,来学习并发工具类CountDownLatch.本文将从CountDownLatch的应用场景.源码原理解析来学习这个并发工具类. 1. 应用场景 CountDownLatch是并 ...

  5. JavaScript是如何工作: 深入探索WebSocket和HTTP/2与SSE + 如何选择正确的路径!

    原文:<JavaScript是如何工作: 深入探索 websocket 和HTTP/2与SSE +如何选择正确的路径! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 文章底部分 ...

  6. hihoCoder编程练习赛52

    题目1 : 字符串排序 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 一般我们在对字符串排序时,都会按照字典序排序.当字符串只包含小写字母时,相当于按字母表" ...

  7. canvas-9NonZeroAroundPrinciples.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. linux (1): 启动

    很早就接触过linux,但是都是一知半解的用,连皮毛都算不上只记得几个命令而已,故决定好好学习一下linux,当前大环境下如果对linux不熟悉或者说不会基本的使用的话,会遇到很多问题. 历史: (大 ...

  9. Ambari架构源码解析

    1. Ambari介绍 Apache Ambari是一种基于Web的工具,支持Apache Hadoop集群的供应.管理和监控.Ambari已支持大多数Hadoop组件,包括HDFS.MapReduc ...

  10. 【vue】使用vue构建多页面应用

    先了解一些单页面和多页面的区别 mm 多页应用模式MPA 单页应用模式SPA 应用构成 由多个完整页面构成 一个外壳页面和多个页面片段构成 跳转方式 页面之间的跳转是从一个页面跳转到另一个页面 页面片 ...