[USACO11OPEN] Corn Maze S
题目链接
注意事项
- 本题解用的是BFS(广度优先搜索),不了解的请先学习一下。
- 传送过去之后不会立即传送回来,传送完毕后,将现在的位置当成草坪即可,但走回传送完毕的位置还是会被传送。
- 传送过去了不要直接打上标记证明走过了,因为有可能还需要传送回去。这里有一个例子:
假设你现在在左下角处,你传送到上面后,可以通过右移再左移传送回左下角,然后右移来到终点处,这样所使用的时间更短。
具体步骤
如果看过上面的提示后,还是存在问题的话,接下来是我的代码,可以参考一下,希望能有帮助。
声明的变量(个人做题习惯使用全局变量,比较方便)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 3e2 + 10;
int m, n;
pii s, e; // 起点和终点
char g[maxn][maxn];
bool vis[maxn][maxn];
int portal[26][5]; // 记录传送门的位置,利用26个空间分别代表26个大写字母
const pii step[4] = { {1,0}, {0,1}, {-1,0}, {0,-1} };
struct Pos // 此处使用结构体记录当时的位置和时间
{
int x, y, t;
Pos() { x = y = t = -1; }
Pos(int xx, int yy, int zz)
{ x = xx, y = yy, t = zz; }
};
输入处理(包含传送门的记录)
int main()
{
cin >> n >> m;
memset(vis, false, sizeof(vis)); // 初始化
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
cin >> g[i][j];
if(g[i][j] == '=')
e = {i,j};
if(g[i][j] == '@')
s = {i,j};
if(g[i][j] <= 'Z' && g[i][j] >= 'A')
UpdatePt(i, j, g[i][j]-'A');
}
cout << BFS() << endl;
return 0;
}
void UpdatePt(int x, int y, int i) // 传入位置和数组下标
{
portal[i][0]++;
if(portal[i][0] == 1) // 如果这是一个新的传送门
{
// 最初的测试点存在单个的传送门,现在这个测试点已经删了,就不用特判这个了
portal[i][1] = portal[i][3] = x;
portal[i][2] = portal[i][4] = y;
}
else if(portal[i][0] == 2) // 如果已经存在,进行匹配
{
portal[i][3] = x;
portal[i][4] = y;
}
}
接下来是BFS主体
void PortalOpen(int &a, int &b, int i) // 传送
{
if(a == portal[i][1] && b == portal[i][2])
a = portal[i][3], b = portal[i][4];
else if(a == portal[i][3] && b == portal[i][4])
a = portal[i][1], b = portal[i][2];
}
int BFS()
{
queue<Pos> q;
q.push(Pos(s.first,s.second,0));
vis[s.first][s.second] = true;
while(!q.empty())
{
Pos now = q.front();
q.pop();
if(now.x == e.first && now.y == e.second) // 到达终点
return now.t;
for(int i = 0; i < 4; i++)
{
int a = now.x + step[i].first;
int b = now.y + step[i].second;
if(a < 0 || b < 0 || a >= n || b >= m || vis[a][b] || g[a][b] == '#')
continue;
vis[a][b] = true;
if(g[a][b] <= 'Z' && g[a][b] >= 'A') // 注意别传送过去就打上true
PortalOpen(a, b, g[a][b] - 'A');
q.push(Pos(a, b, now.t + 1));
}
}
return -1;
}
完整代码
完整代码如下。(未添加注释)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 3e2 + 10;
int m, n;
pii s, e;
char g[maxn][maxn];
bool vis[maxn][maxn];
int portal[26][5];
const pii step[4] = { {1,0}, {0,1}, {-1,0}, {0,-1} };
struct Pos
{
int x, y, t;
Pos() { x = y = t = -1; }
Pos(int xx, int yy, int zz)
{ x = xx, y = yy, t = zz; }
};
void UpdatePt(int x, int y, int i)
{
portal[i][0]++;
if(portal[i][0] == 1)
{
portal[i][1] = portal[i][3] = x;
portal[i][2] = portal[i][4] = y;
}
else if(portal[i][0] == 2)
{
portal[i][3] = x;
portal[i][4] = y;
}
}
void PortalOpen(int &a, int &b, int i)
{
if(a == portal[i][1] && b == portal[i][2])
a = portal[i][3], b = portal[i][4];
else if(a == portal[i][3] && b == portal[i][4])
a = portal[i][1], b = portal[i][2];
}
int BFS()
{
queue<Pos> q;
q.push(Pos(s.first,s.second,0));
vis[s.first][s.second] = true;
while(!q.empty())
{
Pos now = q.front();
q.pop();
if(now.x == e.first && now.y == e.second)
return now.t;
for(int i = 0; i < 4; i++)
{
int a = now.x + step[i].first;
int b = now.y + step[i].second;
if(a < 0 || b < 0 || a >= n || b >= m || vis[a][b] || g[a][b] == '#')
continue;
vis[a][b] = true;
if(g[a][b] <= 'Z' && g[a][b] >= 'A')
PortalOpen(a, b, g[a][b] - 'A');
q.push(Pos(a, b, now.t + 1));
}
}
return -1;
}
int main()
{
cin >> n >> m;
memset(vis, false, sizeof(vis));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
cin >> g[i][j];
if(g[i][j] == '=')
e = {i,j};
if(g[i][j] == '@')
s = {i,j};
if(g[i][j] <= 'Z' && g[i][j] >= 'A')
UpdatePt(i, j, g[i][j]-'A');
}
cout << BFS() << endl;
return 0;
}