1. 程式人生 > 實用技巧 >CF97D Robot in Basement

CF97D Robot in Basement

CF97D Robot in Basement

洛谷傳送門

題意翻譯

在一個n*m(n,m <= 150) 的網格上,有一些格子是障礙的,並且網格邊界上的格子均是障礙的,另有一個非障礙的格子是出口。一個機器人可以根據程式在該網格上行走。一段程式是一個由UDLR四種指令組成的字串,機器人會依次執行每個命令,一個指令會使機器人向指定的方向移動一格,如果對應的格子為障礙則不動,現在給定一格長度為l(l <= 1e5)的程式,求它的一個最短字首p,使得對於一開始的網格上任意非障礙位置都是機器人,在執行完程式p之後都停在出口上。


題解:

暴力的思路是一個一個按序列模擬。但是很容易發現的性質是各個機器人的行動是互相獨立的,不存在誰擋誰路的情況。這樣的話,可以在每個空位都放一個機器人,然後大家同步走,直到大家都重合了並且都到終點了,這時就是最少的步數了。

這也就變成了模擬題。

那麼很自然地想到了用0/1表示有沒有機器人,然後用位運算模擬就行。

模擬的時候大約遵從以下思路:因為bitset沒有二維的,所以先考慮把它對映到一維。然後發現機器人一直在左右上下地動,牆是不動的,比較難維護,所以考慮開3個bitset分別記錄牆、機器人、出口。最後,上下左右的模擬需要在一維狀態下進行,這裡需要特殊注意。

程式碼:

#include<cstdio>
#include<bitset>
using namespace std;
const int maxn=155;
const int maxm=1e5+5;
int n,m,k;
int id[maxn][maxn];
char s[maxm];
bitset<50005> a,b,e,mp;
void init()
{
    int tot=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            id[i][j]=tot++;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
        {
            if(s[j]=='#')
                mp[id[i][j]]=1;
            else
                a[id[i][j]]=1;
            if(s[j]=='E')
                e[id[i][j]]=1;
        }
    }
    scanf("%s",s+1);
    b=a;
    for(int i=1;i<=k+1;i++)
    {
        if(a==e)
        {
            printf("%d\n",i-1);
            return 0;
        }
        if(s[i]=='U')
            a=(((a>>m)&b)|((mp<<m)&a));
        else if(s[i]=='D')
            a=(((a<<m)&b)|((mp>>m)&a));
        else if(s[i]=='L')
            a=(((a>>1)&b)|((mp<<1)&a));
        else 
            a=(((a<<1)&b)|((mp>>1)&a));
    }
    puts("-1");
    return 0;
}