题目大意:在一张图中,以最少的步数将a,b,c移到对应的A,B,C上去。其中,每个2x2的方格都有障碍并且不能两个小写字母同时占据一个格子。

题目分析:为避免超时,先将图中所有能联通的空格建起一张图,然后再BFS。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std; struct Node
{
int t,now[3];
Node(int _t,int a=-1,int b=-1,int c=-1):t(_t){now[0]=a,now[1]=b,now[2]=c;}
bool operator < (const Node &a) const {
return t>a.t;
}
};
struct Edge
{
int to,nxt;
};
Edge e[2000];
char mp[17][17];
int w,h,n,cnt,head[267];
int goal[3],start[3],vis[268][268][268];
int d[5][2]={{0,0},{-1,0},{1,0},{0,1},{0,-1}}; void add(int u,int v)
{
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
} void init()
{
cnt=0;
memset(start,-1,sizeof(start));
memset(goal,-1,sizeof(goal));
memset(head,-1,sizeof(head));
for(int i=0;i<h;++i){
for(int j=0;j<w;++j){
if(mp[i][j]=='#')
continue;
if(mp[i][j]>='a'&&mp[i][j]<='c')
start[mp[i][j]-'a']=i*w+j;
if(mp[i][j]>='A'&&mp[i][j]<='C')
goal[mp[i][j]-'A']=i*w+j;
for(int k=0;k<5;++k){
int ni=i+d[k][0],nj=j+d[k][1];
if(ni>=0&&ni<h&&nj>=0&&nj<w&&mp[ni][nj]!='#')
add(i*w+j,ni*w+nj);
}
}
}
} bool ok(const Node &u)
{
for(int i=0;i<n;++i)
if(u.now[i]!=goal[i])
return false;
return true;
} int bfs()
{
priority_queue<Node>q;
memset(vis,0,sizeof(vis));
vis[start[0]+10][start[1]+10][start[2]+10]=1;
q.push(Node(0,start[0],start[1],start[2]));
while(!q.empty())
{
Node u=q.top();
q.pop(); if(ok(u))
return u.t;
if(n==1){
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]) continue;
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=1;
nxt.t=u.t+1;
q.push(nxt);
}
}else if(n==2){
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
for(int j=head[u.now[1]];j!=-1;j=e[j].nxt){
nxt.now[1]=e[j].to;
if(nxt.now[0]==nxt.now[1]) continue;
if(nxt.now[0]==u.now[1]&&nxt.now[1]==u.now[0]) continue;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]) continue;
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=1;
nxt.t=u.t+1;
q.push(nxt);
}
}
}else{
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
for(int j=head[u.now[1]];j!=-1;j=e[j].nxt){
nxt.now[1]=e[j].to;
if(nxt.now[0]==nxt.now[1]) continue;
if(nxt.now[0]==u.now[1]&&nxt.now[1]==u.now[0]) continue;
for(int k=head[u.now[2]];k!=-1;k=e[k].nxt){
nxt.now[2]=e[k].to;
if(nxt.now[2]==nxt.now[0]||nxt.now[2]==nxt.now[1]) continue;
if(nxt.now[2]==u.now[0]&&nxt.now[0]==u.now[2]) continue;
if(nxt.now[2]==u.now[1]&&nxt.now[1]==u.now[2]) continue;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]) continue;
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=1;
nxt.t=u.t+1;
q.push(nxt);
}
}
}
}
}
} int main()
{
while(scanf("%d%d%d",&w,&h,&n)&&(w+h+n))
{
getchar();
for(int i=0;i<h;++i)
gets(mp[i]);
init();
printf("%d\n",bfs());
}
return 0;
}

  

这道题已知结束状态,还可以使用双向BFS(个人感觉使用双向BFS的效率提升的并不是多明显,从2002ms提到1189ms,也可能是我的代码写得比较挫吧!!!)。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std; struct Node
{
int t,now[3];
Node(int _t,int a=-1,int b=-1,int c=-1):t(_t){now[0]=a,now[1]=b,now[2]=c;}
bool operator < (const Node &a) const {
return t>a.t;
}
};
struct Edge
{
int to,nxt;
};
Edge e[2000];
char mp[17][17];
int w,h,n,cnt,head[267],mark[268][268][268];
int goal[3],start[3],vis[268][268][268];
int d[5][2]={{0,0},{-1,0},{1,0},{0,1},{0,-1}};
priority_queue<Node>q[2]; void add(int u,int v)
{
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
} void init()
{
cnt=0;
memset(start,-1,sizeof(start));
memset(goal,-1,sizeof(goal));
memset(head,-1,sizeof(head));
for(int i=0;i<h;++i){
for(int j=0;j<w;++j){
if(mp[i][j]=='#')
continue;
if(mp[i][j]>='a'&&mp[i][j]<='c')
start[mp[i][j]-'a']=i*w+j;
if(mp[i][j]>='A'&&mp[i][j]<='C')
goal[mp[i][j]-'A']=i*w+j;
for(int k=0;k<5;++k){
int ni=i+d[k][0],nj=j+d[k][1];
if(ni>=0&&ni<h&&nj>=0&&nj<w&&mp[ni][nj]!='#')
add(i*w+j,ni*w+nj);
}
}
}
} int bfs(int id,int step)
{
while(!q[id].empty()){
Node u=q[id].top();
if(u.t!=step)
return -1;
q[id].pop(); if(n==1){
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==-1){
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=id;
mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=u.t+1;
nxt.t=u.t+1;
q[id].push(nxt);
}else if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==!id)
return u.t+1+mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10];
}
}else if(n==2){
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
for(int j=head[u.now[1]];j!=-1;j=e[j].nxt){
nxt.now[1]=e[j].to;
if(nxt.now[0]==nxt.now[1]) continue;
if(nxt.now[0]==u.now[1]&&nxt.now[1]==u.now[0]) continue;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==-1){
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=id;
mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=u.t+1;
nxt.t=u.t+1;
q[id].push(nxt);
}else if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==!id)
return u.t+1+mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10];
}
}
}else{
for(int i=head[u.now[0]];i!=-1;i=e[i].nxt){
Node nxt=u;
nxt.now[0]=e[i].to;
for(int j=head[u.now[1]];j!=-1;j=e[j].nxt){
nxt.now[1]=e[j].to;
if(nxt.now[0]==nxt.now[1]) continue;
if(nxt.now[0]==u.now[1]&&nxt.now[1]==u.now[0]) continue;
for(int k=head[u.now[2]];k!=-1;k=e[k].nxt){
nxt.now[2]=e[k].to;
if(nxt.now[2]==nxt.now[0]||nxt.now[2]==nxt.now[1]) continue;
if(nxt.now[2]==u.now[0]&&nxt.now[0]==u.now[2]) continue;
if(nxt.now[2]==u.now[1]&&nxt.now[1]==u.now[2]) continue;
if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==-1){
vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=id;
mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]=u.t+1;
nxt.t=u.t+1;
q[id].push(nxt);
}else if(vis[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10]==!id)
return u.t+1+mark[nxt.now[0]+10][nxt.now[1]+10][nxt.now[2]+10];
}
}
}
}
}
return -1;
} int solve()
{
while(!q[0].empty())
q[0].pop();
while(!q[1].empty())
q[1].pop();
memset(vis,-1,sizeof(vis));
memset(mark,0,sizeof(mark));
vis[start[0]+10][start[1]+10][start[2]+10]=0;
vis[goal[0]+10][goal[1]+10][goal[2]+10]=1;
q[0].push(Node(0,start[0],start[1],start[2]));
q[1].push(Node(0,goal[0],goal[1],goal[2]));
int step=0;
while(!q[0].empty()||!q[1].empty()){
if(!q[0].empty()){
int k=bfs(0,step);
if(k!=-1)
return k;
}
if(!q[1].empty()){
int k=bfs(1,step);
if(k!=-1)
return k;
}
++step;
}
return -1;
} int main()
{
while(scanf("%d%d%d",&w,&h,&n)&&(w+h+n))
{
getchar();
for(int i=0;i<h;++i)
gets(mp[i]);
init();
printf("%d\n",solve());
}
return 0;
}

  

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

  1. BFS、双向BFS和A*

    BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个 ...

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

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

  3. 小米 oj 马走日 (bfs 或 双向bfs)

     马走日 序号:#56难度:困难时间限制:1500ms内存限制:10M 描述 在中国象棋中,马只能走日字型.现在给出一个由 N*M 个格子组成的中国象棋棋盘( 有(N+1)*(M+1)个交叉点可以落子 ...

  4. UVA - 1601 The Morning after Halloween (BFS/双向BFS/A*)

    题目链接 挺有意思但是代码巨恶心的一道最短路搜索题. 因为图中的结点太多,应当首先考虑把隐式图转化成显式图,即对地图中可以相互连通的点之间连边,建立一个新图(由于每步不需要每个鬼都移动,所以每个点需要 ...

  5. UVA 1601 The Morning after Halloween

    题意: 给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的 ...

  6. UVA 1599 Ideal Path(bfs1+bfs2,双向bfs)

    给一个n个点m条边(<=n<=,<=m<=)的无向图,每条边上都涂有一种颜色.求从结点1到结点n的一条路径,使得经过的边数尽量少,在此前提下,经过边的颜色序列的字典序最小.一对 ...

  7. UVA 1601 双向BFS

    但是我们还不是很清楚每一次的状态怎么储存?我们可以用一个结构体,将每次的位置存起来,但是这个程序中用了一个更好的储存方法:我们知道最大的格数是16*16个,也就是256个,那么我们转换为二进制表示就是 ...

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

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

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

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

  10. ACM-BFS之Open the Lock——hdu1195(双向BFS)

    这道题的0基础版本号,暴力BFS及题目详情请戳:http://blog.csdn.net/lttree/article/details/24658031 上回书说道,要用双向BFS来尝试一下. 最终A ...

随机推荐

  1. Oracle开发 之 主-外键约束FK及约束的修改

    试验环境: 1)数据库版本:oracle 11.2.0.4 2)建表脚本:以scott的dept及emp表为基础. 父表:dept -- Create table create table DEPT ...

  2. D.E.Shaw——高频统计套利交易获利41亿美元

    黑科技,还是要提 D.E.Shaw Research 这个奇异的存在. 要讲这个黑科技,我们可能要扯远一点,先讲讲 D.E. Shaw 这个人是怎么学术赚钱通吃,成为彻底的人生大赢家的. D.E.Sh ...

  3. Mongo副本集的配置以及php node.js连接使用副本集

    最近弄了下mongodb的副本集, 首先说下没有认证情况的副本集,相对比较简单,因为环境有限,我在同一台服务器上做了模拟. --rest参数是打开web监控页面,比如我们这里监听37017端口,则打开 ...

  4. s3对象存储

    bkstorages 模块帮助你在蓝鲸应用中使用多种文件存储服务作为后端,用于加速静态资源,管理用户上传文件. 自定静态文件 storage 如果通过修改配置文件满足不了你的需求,你随时可以通过继承 ...

  5. CF734F Anton and School 构造+数论

    正解:构造 解题报告: 先放下传送门QwQ 这题首先要知道一个结论:(x&y)+(x|y)=x+y 还是能理解的趴? 所以我们把bi+ci就能得到∑a+n*a[i] 然后我们就能成功求出∑a ...

  6. RabbitMQ(转)

    add by zhj: 如果用Python,那可以用celery,它是一个分布式任务队列,它的broker可以选择Rabbitmq/Redis/Mongodb等, celery通过Kombu这个lib ...

  7. What Powers Instagram: Hundreds of Instances, Dozens of Technologies(译文,转)

    add by zhj: 对译文略有修改.原文发表时,Instagram还没被Facebook收购,读完只感觉Instagram这三个后台工程师真牛逼. 三个人就可以搞定1400万注册用户.不过,另一方 ...

  8. CCScene,CCLayer,CCSprite,CCDirector

    一.CCScene : 游戏中不同的画面可以用不同的场景展示出来,大致的可以分为以下的几类场景: 1. 展示类场景.游戏开场画面,游戏简介,胜利以及失败提示,帮助. 2. 选择类场景.主菜单,游戏设置 ...

  9. 利用HBase的快照功能来修改表名

    hbase的快照功能常常被用来做数据的恢复的,但是由于项目的特殊需求需要改hbase表的表名.在官网上通过快照功能来修改hbase表名的用法: 下面展示用shell命令的和Java api两种方式: ...

  10. POI - Excel API

    一.概述    1. Apache POI是Apache软件基金会的开放源码函式库,POI提供API给java程式对Microsoft Office格式档案读和写的功能.    2. 结构       ...