UVa1601 - The Morning after Halloween [单向bfs]
解题思路:
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]的更多相关文章
- UVA - 1601 The Morning after Halloween (双向BFS&单向BFS)
题目: w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...
- POJ1915Knight Moves(单向BFS + 双向BFS)
题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...
- POJ 1915-Knight Moves (单向BFS && 双向BFS 比)
主题链接:Knight Moves 题意:8个方向的 马跳式走法 ,已知起点 和终点,求最短路 研究了一下双向BFS,不是非常难,和普通的BFS一样.双向BFS只是是从 起点和终点同一时候開始搜索,可 ...
- UVA1601 The Morning afther Halloween
题目大意 w h (w, h <= 16)的网格有 n ( n <= 3) 个小写字母(代表鬼)其余的是‘#’(代表障碍格) 或 ‘ ’(代表空格. 要求把他们移动到对应的大写字母里.每步 ...
- UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS && 降维 && 状压)
题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...
- UVA1601-The Morning after Halloween(双向BFS)
Problem UVA1601-The Morning after Halloween Accept: 289 Submit: 3136 Time Limit: 12000 mSec Problem ...
- BFS总结
能够用 BFS 解决的问题,一定不要用 DFS 去做! 因为用 Recursion 实现的 DFS 可能造成 StackOverflow! (NonRecursion 的 DFS 一来你不会写,二来面 ...
- 【HDU3085】nightmare2 双向BFS
对于搜索树分支很多且有明确起点和终点的情况时,可以采用双向搜索来减小搜索树的大小. 对于双向BFS来说,与单向最大的不同是双向BFS需要按层扩展,表示可能到达的区域.而单向BFS则是按照单个节点进行扩 ...
- Word Ladder(双向BFS)
2018-10-02 23:46:38 问题描述: 问题求解: 显然是个解空间遍历问题,每次修改其中一位,由于步长是1,所以可以使用BFS进行解空间的遍历.
随机推荐
- 【水滴石穿】react-native忽略黄色提醒
方法一 import { YellowBox } from 'react-native'; YellowBox.ignoreWarnings(['Remote debugger']); // 忽略黄色 ...
- php中实现多线程的的两个方法具体是怎样?
假设你要建立一个服务来检查正在运行的n台服务器,以确定他们还在正常运转.你可能会写下面这样的代码:代码如下: <?php$hosts = array("host1.sample.com ...
- 调试R代码中出现的常用的函数
1. 字符串连接函数 paste的一般使用格式为: paste(..., sep = " ", collapse = NULL) ...表示一个或多个R可以被转化为字符型的对象:s ...
- 使用淘宝镜像cnpm安装Vue.js
简介: Vue.js是前端一个比较火的MVVM框架, 是一套构建用户界面的渐进式框架. Vue 只关注视图层, 采用自底向上增量开发的设计. Vue 的目标是通过尽可能简单的 API 实现响应的数据绑 ...
- oracle控制何时触发审计动作
1)By session / By Access by session对每个session中发生的重复操作只记录一次 by access对每个session中发生的每次操作都记录,而不管是否重复. 对 ...
- SDUT-3364_欧拉回路
数据结构实验之图论八:欧拉回路 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 在哥尼斯堡的一个公园里,有七座桥将普雷格 ...
- 模拟登录新浪微博(Python) - 转
Update: 如果只是写个小爬虫,访问需要登录的页面,采用填入cookie 的方法吧,简单粗暴有效,详细见:http://www.douban.com/note/264976536/模拟登陆有时需要 ...
- framework7日期插件使用
1.引入框架文件 <link rel="stylesheet" href="framework7.ios.min.css"> <link re ...
- 洛谷2387 BZOJ3669魔法森林题解
题目链接 BZ链接 这道题被很多人用spfa水了过去,表示很... 其实spfa很好卡,这组数据可以卡掉大多数spfa 链接:密码:rjvk 这里讲一下LCT的做法 我们按照a将边排序,然后依次添加 ...
- jQuery 图片高亮显示
主要的jQuery代码: $(function() { $("ul li").hover(function() { // over //鼠标移入当前列透明度为1 其他列为0.5 $ ...