题目描述
她的期末汇报演出就在下周,于是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;
}