【學校集訓】【USACO15DecG】Bessie's Dream

 

點此進入原題php

(注:上面的參考譯文是有問題的,等一下會在題解中說明)算法

算法最短路或搜索(BFS)測試

題解spa

本題用最短路能夠作,可是構圖比較麻煩,搜索要相對簡單一點。code

搜索須要四個量表示狀態:(x,y)座標,一個bool型變量表示是否有橘子味,還有一個量來表示方向(處理紫色方塊時要用)blog

對於當前狀態,若是前一個狀態所在座標表明紫色瓷磚而且能夠繼續滑行(按原方向下一個座標所表明的不是粉紅色或藍色瓷磚),那麼你就要繼續按照原方向滑行。隊列

不然就枚舉4個方向而後按照相應狀況判斷是否有橘子味,以後就是樸素的BFS了~get

重要:本題的讀題坑string

1. 在紫色瓷磚上滑行一次也要步數+1,即便滑到的下一個仍然是紫色瓷磚it

    在參考譯文中寫的「一次滑行不管經過多少瓷磚只算一次移動」顯然是不對的,由於原文是"Sliding through a tile counts as a move",即滑行一個瓷磚算一次移動,而不是不管多少瓷磚。這句話自己好像也通不過去啊……

2. 在初始狀態(1,1)的步數應該是0

    在老師講題的時候說(1,1)的步數應該是1,老師給的AC代碼貌似初始步數也是1,可是我寫的AC代碼初始步數是0,而且若是初始步數是1的話那麼對於第4個測試點會有矛盾。推算原題的意思應該也是初始步數爲0.不過對於老師的代碼能AC我仍是表示十分驚奇的

後來發現老師的代碼裏好像有ans-1?好玄學啊

下面是代碼時間:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1005;
int n,m,a[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
struct Node
{
    int x,y,d;
    bool orange; 
};
queue<Node> q;
int step[N][N][5][3];
bool check(Node f)
{
    int x=dx[f.d]+f.x,y=dy[f.d]+f.y;
    return a[x][y]!=0&&a[x][y]!=3;
}
int main()
{
    freopen("dream.in","r",stdin);
    freopen("dream.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    memset(step,-1,sizeof(step));
    step[1][1][0][0]=step[1][1][2][0]=0; //初始步數爲0
    q.push((Node){1,1,0,false}); //方向爲向下或向右
    q.push((Node){1,1,2,false});
    while(!q.empty())
    {
        Node f=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int x=f.x+dx[i],y=f.y+dy[i];
            if(x<1||y<1||x>n||y>m||a[x][y]==0) continue;
            if(!f.orange&&a[x][y]==3) continue;
            if(a[f.x][f.y]==4&&check(f)) //處理前一個是4的狀況(我直接放在循環內部了)
            {
                if(i!=f.d) continue; //方向要相同
                bool o;
                if(a[x][y]==2) o=true;
                else o=false;
                if(step[x][y][i][o]==-1)
                {
                    step[x][y][i][o]=step[f.x][f.y][i][f.orange]+1; //滑行步數要+1
                    q.push((Node){x,y,i,o});
                }
            }
            else
            {
                bool o;
                if(a[x][y]==2) o=1;
                else if(a[x][y]==4) o=0;
                else o=f.orange;
                if(step[x][y][i][o]!=-1) continue;
                step[x][y][i][o]=step[f.x][f.y][f.d][f.orange]+1;
                q.push((Node){x,y,i,o});
            }
        }
    }
    int ans=1<<30;
    for(int i=0;i<4;i++)
        for(int j=0;j<=1;j++)
            if(step[n][m][i][j]!=-1)
                ans=min(ans,step[n][m][i][j]);
    printf("%d",ans==1<<30?-1:ans);
}

這個代碼在USACO上是能AC的,可是自測會TLE。解決辦法是手寫隊列。然而我懶得手寫了QWQ

彩蛋:貼代碼的時候發現倒數第三行寫的是max QAQ,或許數據中只有一條合法路徑?(驚恐

相關文章
相關標籤/搜索