uva 1601 poj 3523 Morning after holloween 万圣节后的早晨 (经典搜索,双向bfs+预处理优化+状态压缩位运算)
这题数据大容易TLE
优化:预处理, 可以先枚举出5^3的状态然后判断合不合法,但是由于题目说了有很多墙壁,实际上没有那么多要转移的状态那么可以把底图抽出来,然后3个ghost在上面跑到时候就不必判断了,减少了两次无用的枚举。
减少代码的方法:1.结点没有3个时增加冗余点,2.把位置坐标二元组编号成一个数,这点在预处理时可以顺便完成(坐标范围0~15),3.把三个ghost的位置状态压缩成一个数字,方便push,但是注意重时不能直接用Hash掉的值来判断vis,因为Hash以后数字范围很大。
这题为什么不适合Astar。因为Astar的估计用Manhattan距离需要知道坐标,因此不适合把二元组hash成数字,而且不能用一个数来压缩状态了,因为要加上估价值,代码很长,容易写错。
学习点:
1.减少代码量的方法,减少分类,提取不同的问题的相同部分
2.建图的方法。
poj不支持#include<bits/stdc++.h>
//Rey
#include<bits/stdc++.h>
using namespace std;
const int maxw = ;
const int maxn = ;//14*14*3/4+2 149 int s[];
int t[];
int w,h,n;
char maze[maxw][maxw+]; int deg[maxn],G[maxn][]; inline bool conflict(int a1,int b1,int a2,int b2){
return a1 == a2 || (a1 == b2 && a2 == b1);
}
int vis1[maxn][maxn][maxn];
int vis2[maxn][maxn][maxn];
typedef vector<int> VINT;
VINT v1;
VINT v2;
VINT v3;
typedef VINT * PV; inline int Hash(int a,int b,int c) {return a<<|b<<|c;}
int dBfs()
{
v1.clear();v2.clear();v3.clear();
memset(vis1,-,sizeof(vis1));
memset(vis2,-,sizeof(vis2));
PV q1 = &v1,q2 = &v2,nxt = &v3;
int (*d1)[maxn][maxn] = vis1, (*d2)[maxn][maxn] = vis2;
d1[s[]][s[]][s[]] = ;
d2[t[]][t[]][t[]] = ;
q1->push_back(Hash(s[],s[],s[]));
q2->push_back(Hash(t[],t[],t[]));
while(q1->size()&&q2->size()){
if(q1->size()>q2->size()) swap(q1,q2),swap(d1,d2);
for(int ii = ,sz = q1->size(); ii < sz; ii++){
int u = (*q1)[ii];
int a = u>>, b = (u>>)&0xff, c = u&0xff;
for(int i = ; i < deg[a]; i++){
int a1 = G[a][i];
for(int j = ; j < deg[b]; j++){
int b1 = G[b][j];
if(conflict(a1,a,b1,b)) continue;
for(int k = ; k < deg[c]; k++){
int c1 = G[c][k];
if(conflict(c1,c,a1,a)||conflict(c1,c,b1,b)||~d1[a1][b1][c1]) continue;
d1[a1][b1][c1] = d1[a][b][c]+;
if(~d2[a1][b1][c1]) { return d1[a1][b1][c1]+d2[a1][b1][c1]; }
nxt->push_back(Hash(a1,b1,c1));
}
}
}
}
q1->clear();
swap(nxt,q1);
} return -;
} void init()
{
int cnt = ;
int id[maxw][maxw];
const int dx[] = {-, , , , };
const int dy[] = { , ,-, , };
int x[maxn];
int y[maxn]; for(int i = ; i < h; i++)
for(int j = ; j < w; j++) {
char ch = maze[i][j];
if(ch != '#'){
x[cnt] = i; y[cnt] = j; id[i][j] = cnt;
if('A'<= ch && ch <= 'C') {t[ch-'A'] = cnt;}
else if('a' <= ch && ch <= 'c') {s[ch-'a'] = cnt; }
cnt++;
}
} for(int i = ; i < cnt; i++){
deg[i] = ;
for(int k = ; k < ; k++) {
int nx = x[i]+dx[k], ny = y[i]+dy[k];
if(maze[nx][ny] != '#')
G[i][deg[i]++] = id[nx][ny];
}
}
if(n<=) {deg[cnt] = ; G[cnt][] = cnt; s[] = t[] = cnt++; }
if(n<=) {deg[cnt] = ; G[cnt][] = cnt; s[] = t[] = cnt++; }
} int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&w)&&w) {
scanf("%d%d\n",&h,&n);
for(int i = ; i < h; i++)
gets(maze[i]);//G[i-1]
init();
int ans = dBfs();
printf("%d\n",ans);
}
return ;
}
uva 1601 poj 3523 Morning after holloween 万圣节后的早晨 (经典搜索,双向bfs+预处理优化+状态压缩位运算)的更多相关文章
- UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS && 降维 && 状压)
题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...
- 万圣节后的早晨&&九数码游戏——双向广搜
https://www.luogu.org/problemnew/show/P1778 https://www.luogu.org/problemnew/show/P2578 双向广搜. 有固定起点终 ...
- UVa 1601 万圣节后的早晨
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- POJ 3311 Hie with the Pie (BFS+最短路+状态压缩)
题意:类似于TSP问题,只是每个点可以走多次,求回到起点的最短距离(起点为点0). 分析:状态压缩,先预处理各点之间的最短路,然后sum[i][buff]表示在i点,状态为buff时所耗时...... ...
- UVA - 658 It's not a Bug, it's a Feature! (隐式图的最短路,位运算)
隐式的图搜索,存不下边,所以只有枚举转移就行了,因为bug的存在状态可以用二进制表示,转移的时候判断合法可以用位运算优化, 二进制pre[i][0]表示可以出现的bug,那么u&pre[i][ ...
- UVA 658 状态压缩+隐式图+优先队列dijstla
不可多得的好题目啊,我看了别人题解才做出来的,这种题目一看就会做的实在是大神啊,而且我看别人博客都看了好久才明白...还是对状态压缩不是很熟练,理解几个位运算用了好久时间.有些题目自己看着别人的题解做 ...
- <<操作,&0xff以及|的巧妙运用(以POJ3523---The Morning after Halloween(UVa 1601)为例)
<<表示左移,如a<<1表示将a的二进制左移一位,加一个0,&0xff表示取最后8个字节,如a&0xff表示取a表示的二进制中最后8个数字组成一个新的二进制数, ...
- 括号序列问题 uva 1626 poj 1141【区间dp】
首先考虑下面的问题:Code[VS] 3657 我们用以下规则定义一个合法的括号序列: (1)空序列是合法的 (2)假如S是一个合法的序列,则 (S) 和[S]都是合法的 (3)假如A 和 B 都是合 ...
- POJ 1873 UVA 811 The Fortified Forest (凸包 + 状态压缩枚举)
题目链接:UVA 811 Description Once upon a time, in a faraway land, there lived a king. This king owned a ...
随机推荐
- C++的dllexport和dllimport
__declspec(dllexport) 声明一个导出函数,是说这个函数要从本DLL导出.我要给别人用.一般用于dll中省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是C ...
- ps图层混合计算公式
样式效果 http://www.jb51.net/photoshop/104100.html 注释: 1.混合模式的数学计算公式,另外还介绍了不透明度. 2.这些公式仅适用于RGB图像,对于Lab颜色 ...
- 洛谷 P3372 【模板】线段树 1
P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别 ...
- 图论2 最近公共祖先LCA
模板 吸取洛谷P3379的教训,我决定换板子(其实本质都是倍增是一样的),把vector换成了边表 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下 ...
- Delphi调用C# 编写dll动态库
Delphi调用C# 编写dll动态库 编写C#dll的方法都一样,首先在vs2005中创建一个“类库”项目WZPayDll, using System.Runtime.InteropServices ...
- 微信小程序实战
为了积攒粉丝,公司决定做一个一分钱姓名测算的小程序引导大家关注公众号. 实现的需求就是 1 首页 用户编辑姓名和性别进行提交 2 测算结果页 实现分享和支付功能 3 测算历史页面 看到用户曾经测算记 ...
- Yii2.0权限系统,使用PhpManager的方式
网上搜了一大堆yii2.0权限系统,大抵都是千篇一律,而且基本上都是DbManager.看了半天官方文档之后,终于知道了PhpManager的方式下,是怎么引入权限系统.介绍下我自己的使用.首先,配置 ...
- Netty(4)Stream by codec(粘包与拆包)
TCP/IP,传输的是byte[],将byte[]放入队列中.可能会发生粘包和拆包. 比如,客户端向服务端发送了2条消息,分别为D1,D2,可能产生的情况,如下图所示: 情况一:正常的. 情况二:粘包 ...
- LWIP学习之一些细节
一 绑定端口后,开启监听,为何监听还要返回一个新的连接?:监听状态的连接只需要很小的内存,于是tcp_listen()就会收回原始连接的内存,而重新分配一个较小内存块供处于监听状态的连接使用. 二 t ...
- CellSet 遍历
CellSet 结构: 查询MDX: SELECT NON EMPTY {{ {{ {{ {{ {{ AddCalculatedMembers([店铺.店铺ID].[店铺ID].Members)}} ...