洛谷P2206 奶牛芭蕾

题目描述

她的期末汇报演出就在下周,于是Farmer Jhon 就帮她建一个长方形的舞台。

为了防止Bessie从舞台边缘掉下,FJ决定要建一个足够大的舞台。

Bessie的舞蹈将会占用一个由许多1 x 1的正方形方块组成的长方形的区域。为了方便,我们把Bessie的四只脚按如下方式简写:

FR : 前右脚(Front right foot)

FL :前左脚(Front left foot)

RR :后右脚(Rear right foot)

RL :后左脚(Rear left foot)

Bessie将会从一个如下的四个相邻的格子出发,同时她会面向北方。

FL FR

RL RR

Bessie的舞蹈会依据总数为N(1 <= N <= 1000 ) 的指令进行。每一条指令都指示Bessie将一只脚移动一个格子,或者顺时针旋转90°

其中,移动的指示由三个字符组成,其中前两个是脚的代号,最后一个代表脚移动的方向("F" - 向前 "B" - 向后 "R" - 向右 "L" - 向左)

比如说, "FRF"代表着Bessie的前右脚向前移动一个格子,"RLR"代表她的后左脚将向右移一个格子

当然,我们这里说的方向是以Bessie正面对的方向决定的。

另一方面,旋转的指令也是3个字符,其中前两个字母也是脚的代号,代表着旋转的支点。最后一个字母总是为"P"(pivot)。

比如说, "FRP"代表着Bessie将以前右脚为支点,顺时针旋转90°。

如果我们从图中看,假设现在Bessie的脚是这样的,她正朝向北方。

.. .. ..

.. .. FR

.. FL ..

.. RL RR

那么在进行指令"FRP"之后,她的脚的位置将变成下面这样,同时她将会朝向左边:

RL FL ..

RR .. FR

.. .. ..

.. .. ..

现在已知N条Bessie的舞蹈的指令,请你计算她的整个舞蹈所需要的最小的长方形舞台,使得Bessie的脚不会落到舞台之外。

如果无论怎么样,她都会使自己的两个脚移动到相同的格子里,那么她就会被绊倒,并搞砸这次表演。

在这样的情况下,请输出-1。

不过这是Bessie会被绊倒的唯一的原因,因为她在经过练习之后,身体十分的柔软,可以轻松的做到任何奇怪的动作(比如说把后脚伸到前脚的前面)

(吐槽:那你就不能两只脚放在一起?)

(吐槽2:如果你觉得里面的配图有点怪异的话,就把它复制到记事本 ,把字体改成Courier New即可)

输入输出格式

输入格式:

 

第一行是整数N ( 1 <= N <= 1000)

第二至N+1行是如题所述的指令,每行有三个字符

 

输出格式:

 

一行,输出舞台的最小面积

 

输入输出样例

输入样例#1:

3
FRF
FRP
RLB

输出样例#1:

16

 

这道题并不是很难,只是模拟起来很恶心,我们要学会化简模拟,比如说利用转化的思想

其实操作只有两种,一种是某一个脚朝一个方向走一格,另一种是以一只脚为中点顺时针选择90度

我们先想想bessie一开始站在平面直角坐标系上,左后脚站在原点,朝着x的正半轴及上方

为了化简我设定了

b[]分别表示Bessie的四个脚

b[0]表示前左脚
b[1]表示前右脚
b[2]表示后左脚
b[3]表示后右脚

 

pos表示bessie当前的方向

pos=0表示朝上
pos=1表示朝左
pos=2表示朝下
pos=3表示朝右

'F' 'B' 'L' 'R'分别表示操作0,1,2,3

'P‘表示操作4

以下是模拟两种操作的方法

 

操作1:

 这个操作就利用了化简的思想

如果需要走,我们只需要改变当前脚的坐标

不是有搜索矩阵的题目吗,需要往上下左右四个方向搜索

我们也可以利用这种方向的思想,来定义两个数组,一个存x坐标的改变,另一个存y坐标的改变

我用的常量是operax[][]和operay[][]

因此我们可以这样利用两个数组

x+=operax[方向][操作]

y+=operay[方向][操作]

 

操作2:

很显然,操作二是一个难点

我们就利用一个函数:

huan(k,centre)//表示将第k只脚以第cntre为中心旋转90度

那怎么转呢?

首先把固定的那只脚想象成原点,别的脚都有对应的关系

举个例子,我们把固定的脚变成原点,并且假设要旋转的脚是在(1,2)

给个图片:


这个图好像比较大,不过很清楚的看出,点是如何旋转的

设要旋转的点为(x,y),旋转完后变成点(y,-x)

这就是旋转的方法了

下面就是各位最想要的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
using namespace std;
struct zb{
    int x,y;
}B[4];//分别表示Bessie的四个脚
//b[0]表示前左脚
//b[1]表示前右脚
//b[2]表示后左脚
//b[3]表示后右脚
int pos;//表示方向
//pos=0表示朝上
//pos=1表示朝左
//pos=2表示朝下
//pos=3表示朝右
const int operax[4][4]={//opera[pos][order],表示脚往哪个方向走多少步 
    0,0,-1,1,
    -1,1,0,0,
    0,0,1,-1,
    1,-1,0,0};
const int operay[4][4]={
    1,-1,0,0,
    0,0,-1,1,
    -1,1,0,0,
    0,0,1,-1};
char ss[5];
inline int foot(){//根据字符串判断脚 
    if(ss[0]=='F'){
        if(ss[1]=='L')return 0;
        return 1;
    }
    else{
        if(ss[1]=='L')return 2;
        return 3;
    }
}
inline int order(){//判断命令 
         if(ss[2]=='F')return 0;
    else if(ss[2]=='B')return 1;
    else if(ss[2]=='L')return 2;
    else if(ss[2]=='R')return 3;
    return 4;
}
zb n1,n2;
inline void update(){//记录左下角和右上角 
    for(int i=0;i<4;i++)
        n1.x=min(n1.x,B[i].x),
        n1.y=min(n1.y,B[i].y),
        n2.x=max(n2.x,B[i].x),
        n2.y=max(n2.y,B[i].y);
}
inline bool check(int t1){//判断是否有和t1在同位的脚 
    for(int i=0;i<4;i++)if(i!=t1)
        if(B[i].x==B[t1].x&&B[i].y==B[t1].y)
            return 0;
    return 1;
}
inline void huan(int k,int centre){//旋转函数 
    int x=B[k].x-B[centre].x;
    int y=B[k].y-B[centre].y;
    /*   if(x>=0&&y>=0)swap(x,y),y=-y;
    else if(x>=0&&y<=0)swap(x,y),y=-y;
    else if(x<=0&&y<=0)swap(x,y),y=-y;
    else               swap(x,y),y=-y;*/
    swap(x,y),y=-y;
    B[k].x=B[centre].x+x;
    B[k].y=B[centre].y+y;
}
int main(){ 
    B[0]=(zb){0,1};//脚的位置 
    B[1]=(zb){1,1};
    B[2]=(zb){0,0};
    B[3]=(zb){1,0};
    pos=0;
    n1=(zb){ 999999999, 999999999};//初始化 
    n2=(zb){-999999999,-999999999};
    int n,t1,t2;cin>>n;
    bool bk=1;
    while(n--){
        cin>>ss;
        t1=foot();t2=order();
        if(t2!=4){//两种不同的操作 
            B[t1].x+=operax[pos][t2];
            B[t1].y+=operay[pos][t2];
            if(!check(t1)){bk=0;break;}
        }
        else{
            for(int i=0;i<4;i++)if(i!=t1)
                huan(i,t1);
            pos--;if(pos==-1)pos=3;
        }
        update();
    }
    if(bk==0)printf("-1\n");
    else printf("%d\n",(n2.x-n1.x+1)*(n2.y-n1.y+1));//记得+1 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值