解题思路:

1.注意到2*2方格中必有一个#,那么最多只有192条通道,可以将所有非‘#’的位置提取出来用邻接表的方式建图,通过bfs搜索目标位置。

2.将三个ghost的位置(a,b,c)作为状态量存储,如果采用邻接矩阵方式存储图,那么转移代价为5*5*5,很容易超时。分析题意可以知道图中结点大部分不是4个方向都能通过,用邻接表可以避免做多余的判断。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxv=; int di[]={,-,,,};
int dj[]={,,,-,}; int vis[maxv+][maxv+][maxv+];
typedef struct {
int p[]={};
int dist=;
}state; vector<int> G[maxv+];
char buff[][];
int id[][]; int w,h,n,vn,ans;
int ghost_ascii[];
state ghost_init_pos,ghost_target_pos; int read(){
memset(vis, , sizeof vis);
memset(ghost_ascii, , sizeof ghost_ascii);
memset(id, , sizeof id);
memset(buff, , sizeof buff);
memset(ghost_init_pos.p, , sizeof ghost_init_pos.p);
memset(ghost_target_pos.p, , sizeof ghost_target_pos.p);
scanf("%d%d%d",&w,&h,&n);
if(w==) return ; fgets(buff[], , stdin); for(int i=;i<h;i++)
fgets(buff[i], , stdin); vn=;
for(int i=;i<h;i++)
for(int j=;j<w;j++)
if(buff[i][j]!='#'){
vn++;
id[i][j]=vn;
}
char ch;
for(int i=;i<h;i++){
for(int j=;j<w;j++){
ch=buff[i][j]; if(ch!='#'){
int cur=id[i][j]; for(int pos=;pos<;pos++){
int x=i+di[pos],y=j+dj[pos];
if(x>=&&x<h&&y>=&&y<w&&id[x][y]){
int pre=id[x][y];
G[cur].push_back(pre);
}
} if(islower(ch)){
for(int k=;k<n;k++)
if(!ghost_ascii[k]||ghost_ascii[k]==ch){
ghost_ascii[k]=ch;
ghost_init_pos.p[k]=cur;
break;
}
}
else if(isupper(ch)){
for(int k=;k<n;k++){
if(!ghost_ascii[k]||ghost_ascii[k]==ch+'a'-'A'){
ghost_ascii[k]=ch+'a'-'A';
ghost_target_pos.p[k]=cur;
break;
}
}
}
}
}
}
return ;
}
bool check(const state& u,const state& u2){ for(int i=;i<n;i++)
for(int j=i+;j<n;j++)
if(u2.p[i]==u2.p[j]) return false; for(int i=;i<n;i++)
for(int j=i+;j<n;j++)
if(u2.p[i]==u.p[j]&&u2.p[j]==u.p[i]) return false;
return true;
}
void update(queue<state>& q,const state& u,int i,int j=,int k=){
state u2;
u2.p[]=G[u.p[]][i];
if(n>=) u2.p[]=G[u.p[]][j];
if(n==) u2.p[]=G[u.p[]][k];
if(!vis[u2.p[]][u2.p[]][u2.p[]]&&check(u, u2)) {
vis[u2.p[]][u2.p[]][u2.p[]]=;
u2.dist=u.dist+;
q.push(u2);
/*
for(int m=0;m<n;m++)
cout<<u.p[m]<<" ";
cout<<" to ";
for(int m=0;m<n;m++)
cout<<u2.p[m]<<" ";
cout<<u2.dist<<endl;
*/
}
}
void solve(){
queue<state> q;
q.push(ghost_init_pos);
vis[ghost_init_pos.p[]][ghost_init_pos.p[]][ghost_init_pos.p[]]=;
while(!q.empty()){
state u=q.front();q.pop(); if(memcmp(u.p,ghost_target_pos.p,sizeof ghost_target_pos.p)==) {
ans=u.dist;
break;
}
for(int i=;i<G[u.p[]].size();i++){
if(n==){
update(q, u, i);
}
else for(int j=;j<G[u.p[]].size();j++){
if(n==){
update(q, u, i,j);
}
else for(int k=;k<G[u.p[]].size();k++){
update(q, u, i,j,k);
}
}
}
}
printf("%d\n",ans);
} int main() {
while(read()){
solve(); for(int i=;i<=maxv;i++)
G[i].clear();
} return ;
}

UVa1601 - The Morning after Halloween [单向bfs]的更多相关文章

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

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

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

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

  3. POJ 1915-Knight Moves (单向BFS &amp;&amp; 双向BFS 比)

    主题链接:Knight Moves 题意:8个方向的 马跳式走法 ,已知起点 和终点,求最短路 研究了一下双向BFS,不是非常难,和普通的BFS一样.双向BFS只是是从 起点和终点同一时候開始搜索,可 ...

  4. UVA1601 The Morning afther Halloween

    题目大意 w h (w, h <= 16)的网格有 n ( n <= 3) 个小写字母(代表鬼)其余的是‘#’(代表障碍格) 或 ‘ ’(代表空格. 要求把他们移动到对应的大写字母里.每步 ...

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

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

  6. UVA1601-The Morning after Halloween(双向BFS)

    Problem UVA1601-The Morning after Halloween Accept: 289 Submit: 3136 Time Limit: 12000 mSec  Problem ...

  7. BFS总结

    能够用 BFS 解决的问题,一定不要用 DFS 去做! 因为用 Recursion 实现的 DFS 可能造成 StackOverflow! (NonRecursion 的 DFS 一来你不会写,二来面 ...

  8. 【HDU3085】nightmare2 双向BFS

    对于搜索树分支很多且有明确起点和终点的情况时,可以采用双向搜索来减小搜索树的大小. 对于双向BFS来说,与单向最大的不同是双向BFS需要按层扩展,表示可能到达的区域.而单向BFS则是按照单个节点进行扩 ...

  9. Word Ladder(双向BFS)

    2018-10-02 23:46:38 问题描述: 问题求解: 显然是个解空间遍历问题,每次修改其中一位,由于步长是1,所以可以使用BFS进行解空间的遍历.

随机推荐

  1. 【软件安装】我喜欢的notepad插件

    1.文件管理器 explorer 2.16进制查看文件工具 HEX-Editor

  2. ConvertJavaMiliSecondToDateTime

    private static DateTime ConvertJavaMiliSecondToDateTime(long javaMS)        {            DateTime UT ...

  3. java 使用 POI 操作 XWPFDocumen 创建和读取 Office Word 文档基础篇

    注:有不正确的地方还望大神能够指出,抱拳了 老铁! 参考 API:http://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFDoc ...

  4. 【JZOJ1637】【ZJOI2009】狼和羊的故事

    题目描述 "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干 ...

  5. MUI - 解决弹出输入法时页面高度变小导致底部上浮的问题

    解决弹出输入法时页面高度变小导致底部上浮的问题 在有输入框的页面,当输入法弹出的时候,底部元素上浮遮盖了输入框,影响页面美观及功能.查找了一下,页面变窄是不可避免的.即使是设置绝对固定也是不可以的.因 ...

  6. SharpDX初学者教程第2部分:创建窗口

    原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-2-creating-a-window 在第二篇教程中,我们将介绍如何创建一个稍后将呈现的简 ...

  7. 【Flask源码分析——请求上下文与应用上下文】

    Flask中有两种上下文,请求上下文和应用上下文.两者的作用域都处于一个请求的局部中. 查看源代码,上下文类在flask.ctx模块中定义 AppContext类定义应用上下文,app是当前应用Web ...

  8. Hbase数据模型 列族

  9. html实体字符转换成字符串

    function EntityToString(value) { let tag = document.createElement("div"); tag.innerHTML = ...

  10. mysql数据库之多表查询

                                                                            准备                          ...