洛谷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;
}