P3855 [TJOI2008] Binary Land

2024-01-07 23:10
文章标签 binary land p3855 tjoi2008

本文主要是介绍P3855 [TJOI2008] Binary Land,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[TJOI2008] Binary Land

题目背景

Binary Land是一款任天堂红白机上的经典游戏,讲述的是两只相爱的企鹅Gurin和Malon的故事。两只企鹅在一个封闭的迷宫中,你可以控制他们向上下左右四个方向移动。但是他们的移动有一个奇怪的规则,即如果你按“上”或“下”方向键,两只企鹅会同时向上移动或向下移动1格;如果你按“左”方向键,则Malon向左移动1格,同时Gurin向右移动1格;如果你按“右”方向键,则Malon向右移动1格,Gurin向左移动1格。当然,如果某只企鹅被障碍挡住,它就不会移动了。另外,在迷宫的某些格子处有蜘蛛网,如果任何一只企鹅进入这种格子,则游戏失败。两只企鹅不会相互阻挡,即在相向运动时他们可以“穿过”彼此,也可以同时处于同一格子里。迷宫的某个格子上有一颗红心,游戏的任务就是使两只企鹅同时到达这个格子。

题目描述

请编写程序找出完成任务所需的最少的操作步数。如果无法完成目标,输出“no”。

输入格式

第一行包含两个整数R, C 表示迷宫的长和宽。

按下来有R行,每行包含C个字符,描述了一个迷宫。其中’#’表示企鹅不能通过的障碍物,’X’表示蜘蛛网,’.’表示空地,’G’表示Gurin的初始位置,’M’表示Malon的初始位置,’T’表示终点位置。

输入数据保证标有’G’,’M’,’T’的格子分别只有一个,保证企鹅不可能走到迷宫以外。

输出格式

输出只有一行,为最少的操作步数。如果不能完成任务,输出“no”。

样例 #1

样例输入 #1

4 7
#######
#..T..#
#G##M##
#######

样例输出 #1

4

提示

满足要求的一个操作序列为:上-右-左-左

3 ≤ R, C ≤ 30

分析

使用bfs即可,开结构体需记录两只企鹅的坐标,当然还有操作步数

代码

#include <bits/stdc++.h>
using namespace std;
const int M = 35;
int  r, c;
bool st[M][M][M][M];
char g[M][M];
struct point {int x1, y1;int x2, y2;int u;point(int x1=0, int y1=0, int x2=0, int y2=0,int u=0) :x1(x1), y1(y1), x2(x2), y2(y2),u(u) {}
};
queue<point> q;
int lsx, lsy;
point read() {point fi;cin >> r >> c;memset(st, false, sizeof(st));for (int i = 1; i <= r; i++)for (int j = 1; j <= c; j++) {char& tmp = g[i][j];cin >> tmp;if (tmp == 'G') fi.x1 = i, fi.y1 = j;if (tmp == 'M') fi.x2 = i, fi.y2 = j;if (tmp == 'T') lsx = i, lsy = j;}st[fi.x1][fi.y1][fi.x2][fi.y2] = 1;fi.u = 0;return fi;
}
int check(point t) {if (g[t.x1][t.y1] == 'X' or g[t.x2][t.y2] == 'X') return -1;if (g[t.x1][t.y1] == '#' and g[t.x2][t.y2] == '#') return -1;if (g[t.x1][t.y1] == '#') return 1;if (g[t.x2][t.y2] == '#') return 2;return 0;
}
void update1(point t, int i) {point u(t);u.x1 += i; u.x2 += i; bool f = 1; u.u++;switch (check(u)){case 1: {u.x1-=i; break; }case 2: {u.x2-=i; break; }case 0: {break; }default: {f = 0; break; } }if (f and !st[u.x1][u.y1][u.x2][u.y2]) q.push(u), st[u.x1][u.y1][u.x2][u.y2] =  1;
}
void updw(point t) {update1(t, 1);update1(t, -1);
}
void update2(point t, int i,int j) {point u(t);u.y1 += i; u.y2 += j; bool f = 1; u.u++;switch (check(u)){case 1: {u.y1 -= i; break; }case 2: {u.y2 -= j; break; }case 0: {break; }default: {f = 0; break; }}if (f and !st[u.x1][u.y1][u.x2][u.y2]) q.push(u), st[u.x1][u.y1][u.x2][u.y2] = 1;
}
void lfrg(point t) {update2(t, 1, -1);update2(t, -1, 1);
}
int bfs() {q.push(read());while (!q.empty()) {point now = q.front(); q.pop();if (now.x1 == lsx and now.x2 == lsx and now.y1 == lsy and now.y2 == lsy) return now.u;updw(now);lfrg(now);}return -1;
}int main() {int ans = bfs();if (ans == -1) cout << "no";else cout << ans;return 0;
}

代码分析

代码较长,分多部分看
1.bfs

int bfs() {q.push(read());while (!q.empty()) {point now = q.front(); q.pop();if (now.x1 == lsx and now.x2 == lsx and now.y1 == lsy and now.y2 == lsy) return now.u;updw(now);lfrg(now);}return -1;
}

基本的bfs,取队头后再入队其他的值,其中updw(now); lfrg(now);函数的作用分别为尝试上下移动,尝试左右移动
2.updw/lfrg
这两个函数每个都代表了两种操作
由于基本相同,我们只看上下移动的:

void update1(point t, int i) {point u(t);u.x1 += i; u.x2 += i; bool f = 1; u.u++;switch (check(u)){case 1: {u.x1-=i; break; }case 2: {u.x2-=i; break; }case 0: {break; }default: {f = 0; break; } }if (f and !st[u.x1][u.y1][u.x2][u.y2]) q.push(u), st[u.x1][u.y1][u.x2][u.y2] =  1;
}

这是updw函数中调用的函数
首先,我们使状态t进行上下移动,更新步数,后调用check,判断是否合法,此时分4种情况

int check(point t) {if (g[t.x1][t.y1] == 'X' or g[t.x2][t.y2] == 'X') return -1;if (g[t.x1][t.y1] == '#' and g[t.x2][t.y2] == '#') return -1;if (g[t.x1][t.y1] == '#') return 1;if (g[t.x2][t.y2] == '#') return 2;return 0;
}

return 1: 代表第一只企鹅非法移动,所以撤销移动
return 2:同理,第二只企鹅非法移动
return 0:都是合法移动
return -1:都不合法或不存在此状态
最后入队即可

这篇关于P3855 [TJOI2008] Binary Land的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/581558

相关文章

uva 575 Skew Binary(位运算)

求第一个以(2^(k+1)-1)为进制的数。 数据不大,可以直接搞。 代码: #include <stdio.h>#include <string.h>const int maxn = 100 + 5;int main(){char num[maxn];while (scanf("%s", num) == 1){if (num[0] == '0')break;int len =

226 Invert Binary Tree

//226 Invert Binary Tree//算法思路:主要使用递归算法public class Solution {public TreeNode invertTree(TreeNode root) {//1 出口 空节点if (root==null)return null;//2 递归 调用自己TreeNode left = root.left;TreeNode right = ro

[LeetCode] 863. All Nodes Distance K in Binary Tree

题:https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/ 题目大意 求给树中,距给定 结点 指定长度的 所有结点的val 思路 tree -> graph 、 bfs 先遍历树,并用map记录每个结点的父结点 ,将树变为图,然后 bfs。 /*** Definition for a binary tree

LeetCode 67 Add Binary

题意: 两个二进制数相加,输出结果 思路: 各种模拟均可,比如先把A和B倒过来,再按位相加,最后把结果再倒回来。 不过为了快,我是这样做的——假设A比B长,那么我对位相加B的长度。这时如果没有进位,那么A长出B的部分就不会变了;如果有进位,那么继续往A的高位加,直到某一次进位为0,那么更高位的A就不变了;如果直到最后还有进位,那就最前面添加一个最高位1。 代码: cla

Classical Binary Search

Find any position of a target number in a sorted array. Return -1 if target does not exist. Example Example 1: Input: nums = [1,2,2,4,5,5], target = 2Output: 1 or 2 Example 2: Input: nums = [1,

Cousins in binary tree

Input: root = [1,2,3,null,4,null,5], x = 5, y = 4Output: true Input: root = [1,2,3,4], x = 4, y = 3Output: false 思路:就是level order traverse,BFS,记录一下parent, curNode, Depth; /*** Definition for

Average of Levels in Binary Tree

Input:3/ \9 20/ \15 7Output: [3, 14.5, 11]Explanation:The average value of nodes on level 0 is 3, on level 1 is 14.5, and on level 2 is 11. Hence return [3, 14.5, 11]. 思路:就是一个level order trav

Closest Leaf in a Binary Tree

Input:root = [1,2,3,4,null,null,null,5,null,6], k = 2Diagram of binary tree:1/ \2 3/4/5/6Output: 3Explanation: The leaf node with value 3 (and not the leaf node with value 6) is nearest to the no

Binary Tree - Lowest Common Ancestor 题型总结

Lowest Common Ancestor of a Binary Search Tree 思路:这题跟 Lowest Common Ancestor of Binary Tree 一模一样。思路:就是找p的节点在不在左支,或者右支,找到各自左右节点,然后进行比较,如果两者不一样,说明当前的root就是lowest 父节点,如果左边为空,那就都在右边,返回右边的即可,如果右边为空,那就都在左

Android运行时异常“Binary XML file line # : Error inflating class” 发生的几种情况

在原生Android下编译APK,编译没有问题,但是在运行的时候经常出现如标题所描述的异常,然后整个程序蹦掉......     大部分情况是因为修改了资源文件所引起,大致有以下几种方式来解决:     1. 引用类名问题:自定义了一个View,将他用于布局文件中,假设他的包名叫MyPackage,类名叫MyTestView,这个时候你在XML作为布局元素来布局的话,必须使用完整路径名,