點此進入原題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,或許數據中只有一條合法路徑?(驚恐