洛谷 P1825 [USACO11OPEN]玉米田迷宮Corn Maze
題目描述
去年秋天,奶牛們去參觀了一個玉米迷宮,迷宮裡有一些傳送裝置,可以將奶牛從一點到另一點進行瞬間轉移。這些裝置可以雙向使用:一頭奶牛可以從這個裝置的起點立即到此裝置的終點,同時也可以從終點出發,到達這個裝置的起點。如果一頭奶牛處在這個裝置的起點或者終點,這頭奶牛就必須使用這個裝置。
玉米迷宮的外部完全被玉米田包圍,除了唯一的一個出口。
這個迷宮可以表示為N×M的矩陣(2 ≤ N ≤ 300; 2 ≤ M ≤ 300),矩陣中的每個元素都由以下專案中的一項組成:
1、 玉米,這些格子是不可以通過的。
2、 草地,可以簡單的通過。
3、 一個裝置的結點,可以將一頭奶牛傳送到相對應的另一個結點。
4、出口
奶牛僅可以在相鄰兩個格子之間移動,要在這兩個格子不是由玉米組成的前提下才可以移動。奶牛能在一格草地上可能存在的四個相鄰的格子移動。從草地移動到相鄰的一個格子需要花費一個單位的時間,從裝置的一個結點到另一個結點需要花費0個單位時間。
被填充為玉米的格子用“#”表示,草地用“.”表示,每一對裝置的結點由相同的大寫字母組成“A-Z”,且沒有兩個不同裝置的結點用同一個字母表示,出口用“=”表示。
Bessie在這個迷宮中迷路了,她知道她在矩陣中的位置,將Bessie所在的那一塊草地用“@”表示。求出Bessie需要移動到出口處的最短時間。
例如以下矩陣,N=5,M=6:
###=##
#.W.##
#.####
# [email protected]##
######
唯一的一個裝置的結點用大寫字母W表示。
最優方案為:先向右走到裝置的結點,花費一個單位時間,再到裝置的另一個結點上,花費0個單位時間,然後再向右走一個,再向上走一個,到達出口處,總共花費了3個單位時間。
輸入輸出格式
輸入格式:
第一行:兩個用空格隔開的整數N和M;
第2-N+1行:第i+1行描述了迷宮中的第i行的情況(共有M個字元,每個字元中間沒有空格。)
輸出格式:
一個整數,表示Bessie到達終點所需的最短時間。
輸入輸出樣例
輸入樣例#1:5 6
###=##
#.W.##
#.####
#[email protected]##
######
輸出樣例#1: 3
分析
走迷宮加強版,每次多了瞬間傳送的情況,注意判斷細節即可(第一次寫的時候竟然以為只有一個傳送門W 23333).其實我debug了一小時
wwx你要補償我,肉償
程式碼
#include<bits/stdc++.h> using namespace std; char mp[1000][1000]; int book[1000][1000]; int n,m; int beginx,beginy; int move_beginx[30]; int move_beginy[30]; int move_endy[30]; int move_endx[30]; int changex[5]={0,0,1,0,-1}; int changey[5]={0,1,0,-1,0}; struct Point { int x; int y; int step; Point(int _x,int _y,int _step): x(_x),y(_y),step(_step){}//建構函式 }; queue<Point> q; int ans; int flag[30]; int main() { // freopen("testdata.in","r",stdin); cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>mp[i][j]; if(mp[i][j]=='@') { beginx=i; beginy=j; } if(mp[i][j]>='A'&&mp[i][j]<='Z') { if(flag[mp[i][j]-'A']==0) { flag[mp[i][j]-'A']=1; move_beginx[mp[i][j]-'A']=i; move_beginy[mp[i][j]-'A']=j; } else { move_endx[mp[i][j]-'A']=i; move_endy[mp[i][j]-'A']=j; } }//儲存傳送門 } } q.push(Point(beginx,beginy,0)); book[beginx][beginy]=1;//記得起點標記 while(!q.empty()) { Point now_node=q.front(); q.pop(); int now_x=now_node.x; int now_y=now_node.y; // cout<<now_x<<" "<<now_y<<" "<<mp[now_x][now_y]<<endl; int now_step=now_node.step; for(int i=1;i<=4;i++) { int new_x=now_x+changex[i]; int new_y=now_y+changey[i]; if(new_x>n||new_x<1) continue; if(new_y>m||new_y<1) continue; if(mp[new_x][new_y]=='#') continue; if(book[new_x][new_y]==1) continue; book[new_x][new_y]=1; if(mp[new_x][new_y]=='=') { ans=now_step+1; goto u; }//搜到答案 if(mp[new_x][new_y]>='A'&&mp[new_x][new_y]<='Z')//提前打了標記不會存在傳來傳去的情況 { if((new_x==move_beginx[mp[new_x][new_y]-'A'])&&(new_y==move_beginy[mp[new_x][new_y]-'A'])) { if(move_endx[mp[new_x][new_y]-'A']==0) continue; int jump_x=move_endx[mp[new_x][new_y]-'A']; int jump_y=move_endy[mp[new_x][new_y]-'A']; q.push(Point(jump_x,jump_y,now_step+1)); }//傳送門其中一端 else if((new_x==move_endx[mp[new_x][new_y]-'A'])&&(new_y==move_endy[mp[new_x][new_y]-'A'])) { if(move_beginx[mp[new_x][new_y]-'A']==0) continue; int jump_x=move_beginx[mp[new_x][new_y]-'A']; int jump_y=move_beginy[mp[new_x][new_y]-'A'];//不知道為什麼直接賦值給new_x會掛,新開了個變數 q.push(Point(jump_x,jump_y,now_step+1)); }//另一端 }//是傳送門 else { q.push(Point(new_x,new_y,now_step+1)); }//不是傳送門 } } u:cout<<ans<<endl; return 0; }