Escape BNUOJ 49278
2016-04-05 16:47
162 查看
Name: Escape
P_ID: BNUOJ 49278
题目描述:小明进入地下迷宫寻找宝藏,找到宝藏后却发生地震,迷宫各处产生岩浆,小明急忙向出口处逃跑。如果丢下宝藏,小明就能迅速离开迷宫,但小明并不想轻易放弃自己的辛苦所得。所以他急忙联系当程序员的朋友你(当然是用手机联系),并告诉你他所面临的情况,希望你能告诉他是否能成功带着宝藏逃脱。
Input:
有多组测试数据。
每组测试数据第一行是一个整数T,代表接下去的例子数。(0<=T<=10)
接下来是T组例子。
每组例子第一行是两个整数N和M。代表迷宫的大小有N行M列(0<=N,M<=1000)。
接下来是一个N*M的迷宫描述。
S代表小明的所在地。
E代表出口,出口只有一个。
‘.’代表可以行走的地方。
‘!’代表岩浆的产生地。(这样的地方会有多个,其个数小于等于10000)
‘#’代表迷宫中的墙,其不仅能阻挡小明前进也能阻挡岩浆的蔓延。
小明携带者宝藏每秒只能向周围移动一格,小明不能碰触到岩浆(小明不能和岩浆处在同一格)。
岩浆每秒会向四周不是墙的地方蔓延一格。
小明先移动完成后,岩浆才会蔓延到对应的格子里。
小明能移动到出口,则小明顺利逃脱。
Output:
每组测试数据输出只有一行“Yes”或者“No”。 “Yes”代表小明可以成功逃脱。否则输出“No”。
Sample Input
Sample Output
这个题一开始没有自己写出来,看了题解才知道,不过作为第一次遇到双重bfs问题,还是很受用的。
分析:
这个是一道bfs题目,因为要能出去迷宫的话,那肯定是越快越好了,毕竟有岩浆在喷涌。。。
第一反应的思路是在bfs的每次循环中(!queue.empty()),第一步判断当前点是否已经到达了出口,如果是,返回true,否则继续。然后由于题目说了是先人走,后岩浆流动,也就是说如果人和岩浆同时到达某地,那人是可以走的。那么体现在代码上就应该是先对人进行四个方向的判断和入队操作,然后才是对岩浆的传播方向的判断和入队操作。
沿着这个思路,我先大致写了一下,发现问题不小。
人的走动好办,但是岩浆可就不好弄了。我对岩浆的处理是首先遍历迷宫,每遇到’!’就将它向四面流动传播(前提是可以)。但是这么做的话有一个问题。前面的某一个’!’点我对其进行传播后,会导致之后还未扫描到的某个点,由不是岩浆变成了岩浆,等到我扫描它的时候,程序又自动对它进行扩散。这意味着啥?这意味着我这边人刚刚走了一步,那么岩浆就走完了所有的步骤!因为事实上被原来是岩浆的格点所传播变成岩浆的那些格子,在本轮循环中,是不会继续传播的!……好蛋疼。
其实写到这儿就应该有所警觉了。我对两个参考对象分别进行了四个方向的探索,那这个题应该是个啥?
没错,双重bfs。
首先对岩浆用一个bfs,生成岩浆所能到达的所有地方相应的时间。
然后对人用一个bfs,每次除了判断’#’和’.’外,还要判断到达时间是比岩浆早还是晚,比岩浆早,那这个点就可以走,否则就不可以走。
这里有一个问题,一个岩浆向四面传播后,之后的扩散将由子岩浆来完成,也就是说一个岩浆将会且只会扩散传播一次,且传播顺序是按照由父到子的顺序来的,这是啥?没错,队列。也就是第一次的bfs。
先将所有’!’进队,这些全都是初始岩浆。然后开始像四个方向传播,每次成功传播就进队,这么一趟下来,所有进行传播的都是初始岩浆,且初始岩浆也全部出队,剩下的都是子岩浆,然后重复……得到了所有的岩浆可到达点,相应随手保存下到达次序就好。
人的bfs就很常规了,不再赘述,注意判断和岩浆的到达先后。
参考代码:
P_ID: BNUOJ 49278
题目描述:小明进入地下迷宫寻找宝藏,找到宝藏后却发生地震,迷宫各处产生岩浆,小明急忙向出口处逃跑。如果丢下宝藏,小明就能迅速离开迷宫,但小明并不想轻易放弃自己的辛苦所得。所以他急忙联系当程序员的朋友你(当然是用手机联系),并告诉你他所面临的情况,希望你能告诉他是否能成功带着宝藏逃脱。
Input:
有多组测试数据。
每组测试数据第一行是一个整数T,代表接下去的例子数。(0<=T<=10)
接下来是T组例子。
每组例子第一行是两个整数N和M。代表迷宫的大小有N行M列(0<=N,M<=1000)。
接下来是一个N*M的迷宫描述。
S代表小明的所在地。
E代表出口,出口只有一个。
‘.’代表可以行走的地方。
‘!’代表岩浆的产生地。(这样的地方会有多个,其个数小于等于10000)
‘#’代表迷宫中的墙,其不仅能阻挡小明前进也能阻挡岩浆的蔓延。
小明携带者宝藏每秒只能向周围移动一格,小明不能碰触到岩浆(小明不能和岩浆处在同一格)。
岩浆每秒会向四周不是墙的地方蔓延一格。
小明先移动完成后,岩浆才会蔓延到对应的格子里。
小明能移动到出口,则小明顺利逃脱。
Output:
每组测试数据输出只有一行“Yes”或者“No”。 “Yes”代表小明可以成功逃脱。否则输出“No”。
Sample Input
3 5 5 ....! S.... #.... !#... #E... 2 2 S. !E 2 2 SE !.
Sample Output
Yes No Yes
这个题一开始没有自己写出来,看了题解才知道,不过作为第一次遇到双重bfs问题,还是很受用的。
分析:
这个是一道bfs题目,因为要能出去迷宫的话,那肯定是越快越好了,毕竟有岩浆在喷涌。。。
第一反应的思路是在bfs的每次循环中(!queue.empty()),第一步判断当前点是否已经到达了出口,如果是,返回true,否则继续。然后由于题目说了是先人走,后岩浆流动,也就是说如果人和岩浆同时到达某地,那人是可以走的。那么体现在代码上就应该是先对人进行四个方向的判断和入队操作,然后才是对岩浆的传播方向的判断和入队操作。
沿着这个思路,我先大致写了一下,发现问题不小。
人的走动好办,但是岩浆可就不好弄了。我对岩浆的处理是首先遍历迷宫,每遇到’!’就将它向四面流动传播(前提是可以)。但是这么做的话有一个问题。前面的某一个’!’点我对其进行传播后,会导致之后还未扫描到的某个点,由不是岩浆变成了岩浆,等到我扫描它的时候,程序又自动对它进行扩散。这意味着啥?这意味着我这边人刚刚走了一步,那么岩浆就走完了所有的步骤!因为事实上被原来是岩浆的格点所传播变成岩浆的那些格子,在本轮循环中,是不会继续传播的!……好蛋疼。
其实写到这儿就应该有所警觉了。我对两个参考对象分别进行了四个方向的探索,那这个题应该是个啥?
没错,双重bfs。
首先对岩浆用一个bfs,生成岩浆所能到达的所有地方相应的时间。
然后对人用一个bfs,每次除了判断’#’和’.’外,还要判断到达时间是比岩浆早还是晚,比岩浆早,那这个点就可以走,否则就不可以走。
这里有一个问题,一个岩浆向四面传播后,之后的扩散将由子岩浆来完成,也就是说一个岩浆将会且只会扩散传播一次,且传播顺序是按照由父到子的顺序来的,这是啥?没错,队列。也就是第一次的bfs。
先将所有’!’进队,这些全都是初始岩浆。然后开始像四个方向传播,每次成功传播就进队,这么一趟下来,所有进行传播的都是初始岩浆,且初始岩浆也全部出队,剩下的都是子岩浆,然后重复……得到了所有的岩浆可到达点,相应随手保存下到达次序就好。
人的bfs就很常规了,不再赘述,注意判断和岩浆的到达先后。
参考代码:
/** * name: Escape * P_ID: BNUOJ 49278 * date:2014-04-05 */ #include <cstdio> #include <iostream> #include <queue> #include <cstring> using namespace std; int dir[4][2] = {{1,0}, {-1,0}, {0,-1}, {0,1}}; char str[1005][1005]; bool vis[1005][1005]; int dis[1005][1005]; int N, M; int x, y; int ex, ey; const int inf = 0x3f3f3f3f; struct maze { int x; int y; int t; }; bool judge(maze now) { int a = now.x; int b = now.y; if(a<0 || a>=N || b<0 || b>=M) return false; return true; } void bfs_hot() { queue<maze> myHot; for(int i=0; i<N; ++i) { for(int j=0; j<M; ++j) { if(str[i][j]=='!') { dis[i][j] = 0; maze temp; temp.x = i; temp.y = j; temp.t = 0; myHot.push(temp); } } } while(!myHot.empty()) { maze temp = myHot.front(); myHot.pop(); for(int i=0; i<4; ++i) { maze next; next.x = temp.x + dir[i][0]; next.y = temp.y + dir[i][1]; next.t = temp.t + 1; if(judge(next) && next.t<dis[next.x][next.y]) { dis[next.x][next.y] = next.t; myHot.push(next); } } } } bool bfs(int x, int y) { queue<maze> myPath; maze first, next; first.x = x; first.y = y; first.t = 0; myPath.push(first); while(!myPath.empty()) { maze temp = myPath.front(); myPath.pop(); if(temp.x==ex && temp.y==ey) return true; for(int i=0; i<4; ++i) { next.x = temp.x + dir[i][0]; next.y = temp.y + dir[i][1]; next.t = temp.t + 1; if(judge(next) && next.x==ex && next.y==ey && (next.t<=dis[next.x][next.y]))//终点处就算同时到达也算作Yes return true; if(!vis[next.x][next.y] && judge(next) && next.t<dis[next.x][next.y])//中间过程 { vis[next.x][next.y] = 1; myPath.push(next); } } } return false; } int main() { int T; scanf("%d", &T); while(T--) { memset(vis, 0, sizeof(vis)); //配合之后的'#'变更,使得所有岩浆可到达点的dis初始都是inf memset(dis, inf, sizeof(dis)); scanf("%d%d", &N, &M); for(int i=0; i<N; i++) scanf("%s", str[i]); for(int i=0; i<N; ++i) for(int j=0; j<M; j++) { if(str[i][j]=='S') { x = i; y = j; } //用来标记,之后传播岩浆遇到'#'会受阻 if(str[i][j]=='#') { dis[i][j] = 0; } if(str[i][j]=='E') { ex = i; ey = j; } } bfs_hot(); if(bfs(x, y)) printf("Yes\n"); else printf("No\n"); } return 0; }
相关文章推荐
- Java爬虫,信息抓取的实现
- 归并排序
- dedecms 标签
- 哪错的排序
- Cordova插件,自动根据包名替换R资源描述
- swift 类似九宫格
- math3.util.ArithmeticUtils
- POJ 1077 Eight(八数码A*+IDA*)
- Android 全局异常捕获的完整实践
- Codeforces Round #247(Div. 2) C. k-Tree DP
- jquery1.6中的.prop()和.attr()异同
- pojsupermark
- 基本快速排序
- UNICODE,GBK,UTF-8区别
- 新手提问,按F12那个控制台(?)在右边,怎么设置在下边?
- Java开发中的23种设计模式详解
- 构建之法——第四章读后感
- 如何将中缀式转化成前缀式和后缀式
- maven加载本地库
- springMVC+uploadify3.1 文件上传 demo