Uva 1061 The Morning after Halloween
基本思路是BFS:
1. 题目中已经说了,每相连的2X2格子中必有一个‘#’,也就是,每个点周围最多也就三个方向可以走。因此,可以把所有空格都提出来,形成一个图,直接遍历每条边,而不是每次判断4个方向是否可以走
2.关于结点判重,最初的想法是想用一个六维数组,后来参考了其它,发现其实可以用一个三维数字代替,每个点可以用数字代替,因为题目中整个图最多为16X16,所以数字最大为16*16 = 256,这样做的另一个好处是,移动字母也方便了,可以用数字代替点,比如从(0, 0)移动到(0,1)可以考做是从 0 移动到 1
3.N的数量不一,移动时要不要判断是N是多少?这是我刚开始的想法,个人采用递归的方法,先放一个点,再放下一个点,观察这是不是最后一个要移动的点,相对而言,比对每个N值进行单独处理要简单点。
注意点:题目输入的W,H,N中W是指宽度,即列数,而H即为行数。
收获及感悟:刚开始看到这题的时候已经吓着了,首先就是如何保存三个点状态,真的差点用六维数组或map了。在这里也学了一招,用整数依次标记每个点。另外,关于题意,刚开始理解不透,还在想a,b,c三者的先后移动顺序,后来发现想多了,任意顺序移动,判断移动后的状态是否可行即可。这题是在看了别人代码后才A掉的,非常感谢发布题解的同学。
参考资料:
1.http://blog.csdn.net/acm_hkbu/article/details/42420503
2.《算法竞赛入门经典(第2版)》
#include <bits/stdc++.h> using namespace std; const int MAXN = 16 + 5;
char plan[MAXN][MAXN];
int W, H, N;
vector<int> link[MAXN*MAXN];
bool vis[MAXN*MAXN][MAXN*MAXN][MAXN*MAXN];
int dir[4][2] = {0,1, 0,-1, 1,0, -1,0}; struct State{
int ghostPos[5], step;
}; State finalState, firstState; // more than one ghost occupy a same position
// p is the prev state, whether two ghots in s exchange with their position
bool isCollisionOrExChange(State& s, State& p) {
for(int i=0; i<N; ++i) {
for(int j=0; j<N; ++j) {
if(i!=j && s.ghostPos[i] == s.ghostPos[j]) {
return true;
}
if(i!=j && s.ghostPos[i] == p.ghostPos[j] && s.ghostPos[j] == p.ghostPos[i]) {
return true;
}
}
}
return false;
} void Read() {
for(int i=0; i<H; ++i) {
cin.get();
for(int j=0; j<W; ++j) {
plan[i][j] = cin.get();
}
}
} int GetVisValue(int x, int y) {
return x * W + y;
} void SetVis(State& t, bool flag) {
int i, a[3]; // the positon of each ghost
for(i=0; i<N; ++i) {
a[i] = t.ghostPos[i];
}
// the number of ghosts may be less than 3
for(; i<3; ++i) {
a[i] = 0;
}
vis[a[0]][a[1]][a[2]] = flag;
} bool IsVis(State& t) {
int i, a[3]; // the positon of each ghost
for(i=0; i<N; ++i) {
a[i] = t.ghostPos[i];
}
// the number of ghosts may be less than 3
for(; i<3; ++i) {
a[i] = 0;
}
return vis[a[0]][a[1]][a[2]];
} bool IsFinal(State& t) {
for(int i=0; i<N; ++i) {
if(finalState.ghostPos[i] != t.ghostPos[i]) {
return false;
}
}
return true;
} // the ghost numbered g move
void NextState(State& s, int g, queue<State>& q, State& former) {
for(size_t i=0; i<link[former.ghostPos[g]].size(); ++ i) {
s.ghostPos[g] = link[former.ghostPos[g]][i];
if(g == N-1 && !IsVis(s) && !isCollisionOrExChange(s, former)) {
SetVis(s, true);
q.push(s);
} else if (g < N-1) {
NextState(s, g+1, q, former);
}
}
} // output the point of all ghosts
void Test(State& t) {
for(int i=0; i<N; ++i) {
cout << t.ghostPos[i] / W << " " << t.ghostPos[i] % W << endl;
}
cout << t.step << endl;
cout << endl;
} int Bfs() {
memset(vis, false, sizeof(vis));
queue<State> q;
firstState.step = 0;
q.push(firstState);
SetVis(firstState, true);
while(!q.empty()) {
State t = q.front();
q.pop();
// Test(t);
if(IsFinal(t)) {
return t.step;
}
State newS;
newS.step = t.step + 1;
NextState(newS, 0, q, t);
}
return -1;
} // Make a Graph
void MakeLink() {
for(int i=0; i<H; ++ i) {
for(int j=0; j<W; ++ j) {
if(plan[i][j] != '#') {
// the position means unmoving
link[GetVisValue(i, j)].clear();
link[GetVisValue(i, j)].push_back(GetVisValue(i, j));
for(int k=0; k<4; ++k) { // four directions
int x = i + dir[k][0];
int y = j + dir[k][1];
if(x>=0 && x<H && y>=0 && y<W && plan[x][y]!='#') {
link[GetVisValue(i, j)].push_back(GetVisValue(x, y));
}
}
}
if (isupper(plan[i][j])) {
finalState.ghostPos[plan[i][j]-'A'] = GetVisValue(i, j);
} else if (islower(plan[i][j])) {
firstState.ghostPos[plan[i][j]-'a'] = GetVisValue(i, j);
}
}
}
} void Work() {
Read();
MakeLink();
cout << Bfs() << endl;
} int main() {
ios::sync_with_stdio(false);
cin.tie(0);
while(cin >> W >> H >> N) {
if(!W && !H && !N) {
break;
}
Work();
}
return 0;
}
Uva 1061 The Morning after Halloween的更多相关文章
- [uva P1601] The Morning after Halloween
[uva P1601] The Morning after Halloween 题目链接 非常经典的一道题目,lrj的书上也有(貌似是紫书?). 其实这题看起来就比较麻烦.. 首先要保证小鬼不能相遇, ...
- UVA 1601 The Morning after Halloween
题意: 给出一个最大为16×16的迷宫图和至多3个ghost的起始位置和目标位置,求最少经过几轮移动可以使三个ghost都到达目标位置.每轮移动中,每个ghost可以走一步,也可以原地不动,需要注意的 ...
- UVA - 1601 The Morning after Halloween (BFS/双向BFS/A*)
题目链接 挺有意思但是代码巨恶心的一道最短路搜索题. 因为图中的结点太多,应当首先考虑把隐式图转化成显式图,即对地图中可以相互连通的点之间连边,建立一个新图(由于每步不需要每个鬼都移动,所以每个点需要 ...
- UVA - 1601 The Morning after Halloween (双向BFS&单向BFS)
题目: w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...
- <<操作,&0xff以及|的巧妙运用(以POJ3523---The Morning after Halloween(UVa 1601)为例)
<<表示左移,如a<<1表示将a的二进制左移一位,加一个0,&0xff表示取最后8个字节,如a&0xff表示取a表示的二进制中最后8个数字组成一个新的二进制数, ...
- uva 11237 - Halloween treats(抽屉原理)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u011328934/article/details/37612503 题目链接:uva 11237 ...
- UVA 11237 - Halloween treats(鸽笼原理)
11237 - Halloween treats option=com_onlinejudge&Itemid=8&page=show_problem&category=516& ...
- UVa 1601 || POJ 3523 The Morning after Halloween (BFS || 双向BFS && 降维 && 状压)
题意 :w*h(w,h≤16)网格上有n(n≤3)个小写字母(代表鬼).要求把它们分别移动到对应的大写字母里.每步可以有多个鬼同时移动(均为往上下左右4个方向之一移动),但每步结束之后任何两个鬼不能占 ...
- 【UVa】1601 The Morning after Halloween(双向bfs)
题目 题目 分析 双向bfs,对着书打的,我还调了好久. 代码 #include<cstdio> #include<cstring> #include<c ...
随机推荐
- Android学习笔记(一)开发环境搭建
Android开发环境搭建 安装JDK 1.如果你还没有JDK的话,可以去这里http://www.oracle.com/technetwork/java/index.html ,接下来的工作就是安装 ...
- MSSQL数据库统计所有表的记录数
今天需要筛选出来库中行数不为零的表,于是动手写下了如下存储过程. CREATE PROCEDURE TableCount AS BEGIN SET NOCOUNT ON ),RowsCount INT ...
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (四) —— ContentProvider
ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制.一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制.并且此种方式忽略了底层的数据存储实现,Cont ...
- POJ 1840 Brainman(逆序对数)
题目链接:http://poj.org/problem?id=1804 题意:给定一个序列a[],每次只允许交换相邻两个数,最少要交换多少次才能把它变成非递降序列. 思路:题目就是要求逆序对数,我们知 ...
- ThinkPHP第二十天(getField用法、常用管理员表结构、树形结构前小图标CSS)
1.getField($fields,$sepa=null) A:当$fields为1个字段,$sepa=null的时候,返回一个符合条件的记录的字段. B:如果要取得所有符合条件记录字段,需要$se ...
- jmeter cookie管理器 使用方法---新手学习记录1
首先得抓包: 我已post方法为例: POST /api/datasources/lemontest/jaql HTTP/1.1 Host: 192.168.1.107:8081 Content-Le ...
- BZOJ 1005 明明的烦恼 (组合数学)
题解:n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数. 则 所以要求在n-2大小的数组中插入tot各序号,共有种插法: 在tot各序号排列中,插第一个节点的 ...
- 汇编语言学习——第二章 寄存器(CPU工作原理)
1.一个典型的CPU由运算器.控制器.寄存器等器件组成,这些器件靠内部总线相连. 区别: 内部总线实现CPU内部各个器件之间的联系. 外部总线实现CPU和主板上其它器件的联系. 8086CPU有14个 ...
- Android中GridView的使用——使用自带的SimpleAdapter(简单适配器)
GridView一直是一个系统登录后以九宫格方式展现功能子模块的最佳选择,经过试验和网上资料的查阅,现把实现方式总结一下: 一直是通过自定义Adapter方式,在getView()方法中设置图片的显示 ...
- Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)
我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...