洛谷 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.##
#.####
#.@W##
######
唯一的一个装置的结点用大写字母W表示。
最优方案为:先向右走到装置的结点,花费一个单位时间,再到装置的另一个结点上,花费0个单位时间,然后再向右走一个,再向上走一个,到达出口处,总共花费了3个单位时间。
输入输出格式
输入格式:
第一行:两个用空格隔开的整数N和M;
第2-N+1行:第i+1行描述了迷宫中的第i行的情况(共有M个字符,每个字符中间没有空格。)
输出格式:
一个整数,表示Bessie到达终点所需的最短时间。
输入输出样例
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; }