Atcoder FT robot解題報告

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 ofF and T.
  • 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.



發佈了79 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章