Atcoder FT robot解題報告
題目原文
A robot is put at the origin in a two-dimensional plane.Initially, the robot is facing in the positivex-axis direction.
This robot will be given an instruction sequence s.s consists of the following two kinds of letters, and will be executed in order from front to back.
F
: Move in the current direction by distance1.T
: Turn 90 degrees, either clockwise or counterclockwise.
The objective of the robot is to be at coordinates(x,y) after all the instructions are executed.Determine whether this objective is achievable.
Constraints
- s consists of
F
andT
. - 1≤|s|≤8000
- x andy are integers.
- |x|,|y|≤|s|
題意分析
一個機器人按照S中的指令行動,T代表轉90度,順時針或逆時針,F代表向前一步。給定目標x和y,求機器人通過所有操作之後是否能到達目標地點。
解法分析
本題採用兩種解法:
- 動態規劃
- bit manipulation
動態規劃
由於遇到一個T,則x和y切換,因此可以分別求出在x和y的前進步數,用vector vx和vy存儲,此時並不知道前進方向,只記錄了在同一個方向每次前進的步數。採用自底向上的動態規劃,單看x軸上的行動,vx的大小爲N,整個活動範圍長度爲16001,DP[N][16001],則初始原點值爲1,即DP[0][8000]=1,DP[i][j]=DP[i-1][j+vx[i]]||DP[i-1][j-vx[i]],由於i遞增,則可以用一個DP[2][16001]來代替上述二維數組。C++代碼如下:
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<algorithm>
#include<cstring>//memset needs this head
using namespace std;
int canReach[2][16001];
bool DP(vector<int> v,int t,int start){//v is the step vector of each axis
memset(canReach,0,sizeof(canReach));
canReach[0][8000+start]=1;//the initial place
if(v.size()==0)
return canReach[0][8000+t];
int i;
for(i=1;i<=v.size();i++){
for(int j=0;j<=16000;j++){
canReach[i%2][j]=((j+v[i-1])>16000?0:canReach[(i-1)%2][j+v[i-1]])||((j-v[i-1])<0?0:canReach[(i-1)%2][j-v[i-1]]);
}
}
return canReach[(i-1)%2][8000+t];
}
int main(){
string S;
int tx,ty;
cin>>S>>tx>>ty;
bool whichAxis=0;//the initial axis is x,1 is y;
vector<int> vx;
vector<int> vy;
int count=0;
for(auto c:S){
if(c=='T'){
((whichAxis==0)?vx:vy).push_back(count);
count=0;
whichAxis=!whichAxis;
}
else{
count++;
}
}
((whichAxis==0)?vx:vy).push_back(count);//that is important,the last several T's
// tx-=vx[0];//the first several step in x have decided direction.That is an error
int start=vx[0];
vx.erase(vx.begin());
if(DP(vx,tx,start)&&DP(vy,ty,0))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}
其中注意memset的頭文件爲cstring ,且memset是按字節賦值,所以如果數組元素爲char,則可以隨意賦值,如果爲int,則只能賦值爲0和-1,因爲這兩個數的每字節是相同的(當然也能賦其他個字節相同的數)。值得注意的是對於x,vx[0]的方向是確定的,所以應該直接將canReach[0][8000+vx[0]]賦值爲1,同時將vx[0]erase掉,不然如將vx直接送入DP中,會造成錯誤結果,如vx[0]=1,則會錯誤的將canReach[1][-1]判斷爲1,同時,不能直接將tx賦值爲tx-vx[0],因爲如果vx[0]=-8000,則會造成canReach數組越界,得到runtime
error。
Bitmanipulation
本題如採用bit操作,模擬機器人移動的過程,需要引入bitset,bitset對象的定義方式如下:
bitset<n> a;//定義長度爲n的bitset對象,各位位0;
bitset<n> a(b);//用unsigned long型變量來初始化a,a的低字節爲index=0的那邊,則將b的低字節向a中填充,不夠則向高位填0,超出則截斷。
bitset<n> a(s);//用二進制字符串s來初始化a。
a有多種操作,如a.set(),全部置1,a.reset()全部置0,a.flip()全部翻轉,當然也能對每個下標bit做上述操作。
本題C++代碼如下:
#include <iostream>
#include <cstdio>
#include <bitset>
#define M 8005
using namespace std;
int x, y, z, c;
string s;
bitset<M * 2> bs[2];
int main() {
int i;
cin >> s >> x >> y;
for (i = 0; s[i] == 'F'; i++);
bs[0][i + M] = bs[1][M] = 1;
for (; i <= s.size(); i++) {
if (s[i] == 'F') c++;
else bs[z] = (bs[z] << c) | (bs[z] >> c), z = !z, c = 0;
}
cout << (bs[0][x + M] & bs[1][y + M] ? "Yes" : "No");
return 0;
}
將所有可能達到的位都置1.