20180610模拟赛T1——脱离地牢

Description

在一个神秘的国度里,年轻的王子Paris与美丽的公主Helen在一起过着幸福的生活。他们都随身带有一块带磁性的阴阳魔法石,身居地狱的魔王Satan早就想着得到这两块石头了,只要把它们溶化,Satan就能吸收其精华大增自己的魔力。于是有一天他趁二人不留意,把他们带到了自己的地牢,分别困在了不同的地方。然后Satan念起了咒语,准备炼狱,界时二人都将葬身于这地牢里。 危险!Paris与Helen都知道了Satan的意图,他们要怎样才能打败魔王,脱离地牢呢?Paris想起了父王临终前给他的备忘本,原来他早已料到了Satan的野心,他告诉Paris只要把两块魔法石合在一起,念出咒语,它们便会放出无限的光荣,杀死魔王,脱离地牢,而且本子上还附下了地牢的地图,Paris从中了解到了Helen的位置所在。于是他决定首先要找到Helen,但是他发现这个地牢很奇怪,它会增强二人魔法石所带的磁力大小,而且会改变磁力的方向。这就是说,每当Paris向南走一步,Helen有可能会被石头吸引向北走一步。而这个地狱布满了岩石与熔浆,Paris必须十分小心,不仅他不能走到岩石或熔浆上,而且由于他行走一步,Helen的位置也会改变,如果Helen碰到岩石上,那么她将停留在原地,但如果Helen移动到了熔浆上,那么她将死去,Paris就找不到她了。 Paris仔细分析了地图,他找出了一条最快的行走方案,最终与Helen相聚。他们一起念出了咒语“·#¥%^…*&@!”,轰隆一声,地牢塌陷了,他们又重见光明…

Input

输入数据第一行为两个整数n,m(3<=n,m<=20),表示地牢的大小,n行m列。接下来n行,每行m个字符,描述了cf地牢的地图,“.”代表通路,“#”代表岩石,“!”代表熔浆,“H”表示Helen,“P”表示Paris。输入保证地牢是封闭的,即四周均是岩石或熔浆。接下来一行有四个字符“N”(北),“S”(南),“W”(西),“E”(东)的排列,表示Paris分别向NSWE四个方向走时Helen受磁石磁力影响的移动方向。

Output

输出文件只有一行,如果Paris能找到Helen,输出一整数d,为Paris最少需要行走的步数;如果Paris在255步之后仍找不到Helen,则输出“Impossible”。注意相遇是指Paris与Helen最终到达同一个格子,或者二人在相邻两格移动后碰到了一起,而后者的步数算他们移动后的步数。

Sample Input

5 5
#####
#H..#
#.!.#
#.#P#
#####
WNSE

Sample Output

5

题解

话说这几天每次模拟赛怎么都有一道搜索……

裸的bfs。然而交上去只有奇怪的80分,发现是没注意这句话:

注意相遇是指Paris与Helen最终到达同一个格子,或者二人在相邻两格移动后碰到了一起,而后者的步数算他们移动后的步数。

就是如果Paris从A到B,Helen从B到A,那么也算碰到了一起。

于是这个需要判一下。

感觉没什么好讲的了,就直接上代码吧。

#include <cstdio>
#include <queue>

using namespace std;

const int maxn = 25;

int n, m;

char mmap[maxn][maxn];
bool vis[maxn][maxn][maxn][maxn];//直接记录状态

struct sxd//这是机房大佬,请不要在意
{
    int hi, hj, pi, pj;
    int bs;
};

const int diri[] = {-1, 1, 0, 0};
const int dirj[] = {0, 0, -1, 1};
int dirhi[5];
int dirhj[5];

int main()
{
    freopen("escape.in", "r", stdin);
    freopen("escape.out", "w", stdout);
    scanf("%d%d\n", &n, &m);
    sxd first;
    first.bs = 0;
    for(int i = 0; i < n; ++i)
    {
        gets(mmap[i]);
        for(int j = 0; j < m; ++j)
        {
            if(mmap[i][j] == 'H')
            {
                first.hi = i;
                first.hj = j;
                mmap[i][j] = '.';
            }
            else if(mmap[i][j] == 'P')
            {
                first.pi = i;
                first.pj = j;
                mmap[i][j] = '.';
            }
        }
    }
    queue<sxd> Q;
    Q.push(first);
    vis[first.pi][first.pj][first.hi][first.hj] = true;
    char tmp[5];
    gets(tmp);
    for(int i = 0; i < 4; ++i)
    {
        switch(tmp[i])
        {
            case 'W':
                dirhi[i] = 0;
                dirhj[i] = -1;
                break;
            case 'N':
                dirhi[i] = -1;
                dirhj[i] = 0;
                break;
            case 'S':
                dirhi[i] = 1;
                dirhj[i] = 0;
                break;
            case 'E':
                dirhi[i] = 0;
                dirhj[i] = 1;
                break;
        }
    }
    while(!Q.empty())
    {
        sxd now = Q.front();
        Q.pop();
        if(now.bs > 255)
            break;
        for(int i = 0; i < 4; ++i)
        {
            sxd nxt = now;
            nxt.bs++;
            nxt.pi += diri[i];
            nxt.pj += dirj[i];
            nxt.hi += dirhi[i];
            nxt.hj += dirhj[i];
            if(nxt.hi == now.pi && nxt.hj == now.pj && nxt.hj == now.pj && now.hi == nxt.pi)//注意判交错情况
            {
                printf("%d", nxt.bs);
                fclose(stdin);
                fclose(stdout);
                return 0;
            }
            if(mmap[nxt.pi][nxt.pj] != '.' || mmap[nxt.hi][nxt.hj] == '!')
                continue;
            if(mmap[nxt.hi][nxt.hj] == '#')//注意Helen是可以撞墙的。
            {
                nxt.hi = now.hi;
                nxt.hj = now.hj;
            }
            if(nxt.hi == nxt.pi && nxt.hj == nxt.pj)
            {
                printf("%d", nxt.bs);
                fclose(stdin);
                fclose(stdout);
                return 0;
            }
            if(!vis[nxt.pi][nxt.pj][nxt.hi][nxt.hj])
            {
                Q.push(nxt);
                vis[nxt.pi][nxt.pj][nxt.hi][nxt.hj] = true;
            }
        }
    }
    puts("Impossible");
    fclose(stdin);
    fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/pfypfy/p/9163965.html

时间: 2024-08-02 04:06:52

20180610模拟赛T1——脱离地牢的相关文章

2017 11 6模拟赛T1

作为一个毒瘤出题人(wzy:我不是毒瘤出题人,这些题明明很水的),wzy的题干十分复杂,但是把题意简化之后,相当简单粗暴... 求首项为1,等比为m,项数为t的等比数列的和,答案对k取模 不保证m与k互质 如果m与k互质的话,用等比数列的求和公式在求个逆元就能解决了,但是本题显然不能,于是必须考虑不含有除法的算法 于是就有了分治求等比数列和的办法. 设s(x)为等比数列的第n项 由等比数列的性质得到s(y)=s(x)*m^(y-x) (y>x) 将一个长度为2r的等比数列拆分成登场的两部分,对应

[模拟赛] T1 高级打字机

Description 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. Input 第1行:一个整数n,表示操作数量. 以下n行,每行一个命令.保证输入的命令合法

校内模拟赛T1大美江湖

这就是一个模拟题,注意1234分别对应左右上下横坐标和纵坐标的判断就好了 题解: 需要注意的是,向上取整ceil函数是对于一个double值返回一个double值,也就是说在ceil里面的类型一定要是double,否则会炸 代码: #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<string>

【2019.8.15 慈溪模拟赛 T1】插头(plugin)(二分+贪心)

二分 首先,可以发现,最后的答案显然满足可二分性,因此我们可以二分答案. 然后,我们只要贪心,就可以验证了. 贪心 不难发现,肯定会优先选择能提供更多插座的排插,且在确定充电器个数的情况下,肯定选择能经过排插数量最大的那些充电器. 所以,我们只要模拟插排插的过程,记录当前深度\(d\).插座数\(t\)即可. 设选择的能经过排插数量恰好为\(d\)的充电器有\(x\)个,则若\(t<x\),显然不合法. 否则,我们将\(x\)个位置插上充电器,其余位置尽可能地插排插,就可以了. 代码 #incl

[10.5模拟赛]T1

T1 Description 在\(2019\)年,某小朋友刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为\(1\)),有以下两种操作: 标记操作:对某个结点打上标记(在最开始,只有结点\(1\)有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.) 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先) 你能帮帮他吗? Input 输入第一行两个正整数\(N\)和\(Q\)分别表示节点个数和操作次数 接下来\(N-1\)行,每行两个正整数\

2017-9-3模拟赛T1 卡片(card)

题目 [题目描述] lrb 喜欢玩卡牌.他手上现在有n张牌,每张牌的颜色为红绿蓝中的一种.现在他有两种操作.一是可以将两张任意位置的不同色的牌换成一张第三种颜色的牌:二是可以将任意位置的两张相同颜色的牌换成一张该颜色的牌.两个操作后都可以将生成的牌放到任意位置.现在他想知道,最后一张牌可能是什么颜色的. [输入描述] 第一入一个n,表示卡牌数量.第二行输入一个由'B','G','R'组成的长度为n的字符串,分别表示卡牌的颜色为蓝色.绿色.红色中的一种.[输出描述]输出'B','G','R'中的若

洛谷 U360 子矩阵 (NOIP模拟赛T1)题解

题目链接:https://www.luogu.org/problem/show?pid=U360 题目背景 夏令营 题目描述 小A有一个N×M的矩阵,矩阵中1~N*M这(N*M)个整数均出现过一次.现在小A在这个矩阵内选择一个子矩阵,其权值等于这个子矩阵中的所有数的最小值.小A想知道,如果他选择的子矩阵的权值为i(1<=i<=N×M),那么他选择的子矩阵可能有多少种?小A希望知道所有可能的i值对应的结果,但是这些结果太多了,他算不了,因此他向你求助. 输入输出格式 输入格式: 第一行,两个整数

字符串模拟赛T1

// source code from laekov for c0x17 #define PRID "bxjl" #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long dint; const int maxn = 100003; const int mod = 998244353; char a[maxn]; i

11.12 模拟赛T1 加密

[问题描述] 有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符. 相应的, 不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符. 给定原文?和加密后的字符串?,求?有多少子串可以通过解密得到原文?. [输入格式] 输入第一行包含一个字符串?,第二行包含一个字符串?. [输出格式] 输出一行,包含一个整数,代表可以通过解密得到原文的?的子串的数量. [样例输入] abcabcabccba [样例输出] 9 [样例解释] 用[l,r]表示子串开头结尾的下标(从 0 开始编号) ,