P1825 Corn Maze S
P1825 Corn Maze S
无脑深搜,然后卡死在了37pts。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
struct coord {
int x, y;
};
int walk[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, sx, sy, ans = 0x7fffffff;
char map[301][301];
coord tpGate[100][2];
int cnt[100];
bool vis[301][301];
bool use_gate[100];
bool is_tp(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
void findTpEnd(int ch, int x, int y,int& dx, int& dy)
{
if (tpGate[ch][0].x == x && tpGate[ch][0].y == y)
{
dx = tpGate[ch][1].x, dy = tpGate[ch][1].y;
return ;
}
else
{
dx = tpGate[ch][0].x, dy = tpGate[ch][0].y;
return ;
}
}
void dfs(int step, int x, int y)
{
if (step > ans)
{
return ;
}
if (map[x][y] == '=')
{
ans = min(ans, step);
return;
}
int temp = (int)map[x][y];
if (is_tp(map[x][y]))
{
int tx, ty;
findTpEnd(temp, x, y, tx, ty);
if (!vis[tx][ty])
{
vis[tx][ty] = true;
dfs(step, tx, ty);
vis[tx][ty] = false;
return ;
}
}
for (int i = 0; i < 4; i++)
{
int dx = x + walk[i][0], dy = y + walk[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || vis[dx][dy] || map[dx][dy] == '#') continue;
vis[dx][dy] = true;
dfs(step + 1, dx, dy);
vis[dx][dy] = false;
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> map[i][j];
if (is_tp(map[i][j]))
{
int temp = map[i][j];
tpGate[temp][cnt[temp]].x = i;
tpGate[temp][cnt[temp]].y = j;
cnt[temp]++;
}
if (map[i][j] == '@')
{
sx = i, sy = j;
}
}
}
dfs(0, sx, sy);
printf("%d", ans);
return 0;
}
找到传送门标记问题
T了几个点,WA了几个点,想到说传送门是可能再次使用的,不能用vis数组来判断,但细想下来,主要是传过去之后不能立马传回来,但是可能走一段之后再回到这个传送门,所以传送到的传送门是不能标记的。基于这个思想,我选择特判进入dfs时是否是传送门,是的话说明刚传到不能标记,否则就标记
改完后没有正确性问题了,\(55pts\),T了一半。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
struct coord {
int x, y;
};
int walk[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, sx, sy, ans = 0x7fffffff;
char map[301][301];
coord tpGate[100][2];
int cnt[100];
bool vis[301][301];
bool use_gate[100];
bool is_tp(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
void findTpEnd(int ch, int x, int y,int& dx, int& dy)
{
if (tpGate[ch][0].x == x && tpGate[ch][0].y == y)
{
dx = tpGate[ch][1].x, dy = tpGate[ch][1].y;
return ;
}
else
{
dx = tpGate[ch][0].x, dy = tpGate[ch][0].y;
return ;
}
}
void dfs(int step, int x, int y)
{
if (!is_tp(map[x][y]))
{
vis[x][y] = true;
}
if (step > ans)
{
return ;
}
if (map[x][y] == '=')
{
ans = min(ans, step);
return;
}
for (int i = 0; i < 4; i++)
{
int dx = x + walk[i][0], dy = y + walk[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || vis[dx][dy] || map[dx][dy] == '#') continue;
if (is_tp(map[dx][dy]))
{
int tx, ty;
int temp = (int)map[dx][dy];
findTpEnd(temp, dx, dy, tx, ty);
if (cnt[temp] == 2)
{
vis[dx][dy] = true;
dfs(step + 1, tx, ty);
vis[dx][dy] = false;
} else {
dfs(step + 1, dx, dy);
vis[dx][dy] = false;
}
} else {
dfs(step + 1, dx, dy);
vis[dx][dy] = false;
}
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> map[i][j];
if (is_tp(map[i][j]))
{
int temp = map[i][j];
tpGate[temp][cnt[temp]].x = i;
tpGate[temp][cnt[temp]].y = j;
cnt[temp]++;
}
if (map[i][j] == '@')
{
sx = i, sy = j;
}
}
}
dfs(0, sx, sy);
printf("%d", ans);
return 0;
}
使用算法错误
想想怎么记忆化搜索或者剪枝优化吧。
然而几乎是毫无思路了,因为传送门的存在,我想不到很优秀的记忆化状态,剪枝大概率也是玄学。
点开这道题标签,猛然看见BFS和最短路。
这才意识到这题用BFS更好,毕竟BFS的特性让他在求最短路径的时候有远超DFS的优势。
于是又开始打BFS。
因为觉得大同小异,所以几乎是直接把DFS代码复制了过去,但是却又T又M。
\(67pts\) code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
struct coord {
int x, y;
};
struct status {
int x, y, step;
};
int walk[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, sx, sy, ans = 0x7fffffff;
char map[301][301];
coord tpGate[100][2];
queue<status> Q;
int cnt[100];
int ansArr[301][301];
bool vis[301][301];
bool is_tp(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
void findTpEnd(int ch, int x, int y,int& dx, int& dy)
{
if (tpGate[ch][0].x == x && tpGate[ch][0].y == y)
{
dx = tpGate[ch][1].x, dy = tpGate[ch][1].y;
return ;
}
else
{
dx = tpGate[ch][0].x, dy = tpGate[ch][0].y;
return ;
}
}
void BFS()
{
Q.push({sx, sy, 0});
while(!Q.empty())
{
status node = Q.front();
Q.pop();
int x = node.x, y = node.y, step = node.step;
if (!is_tp(map[x][y]))
{
vis[x][y] = true;
}
if (map[x][y] == '=')
{
ans = step;
return ;
}
for (int i = 0; i < 4; i++)
{
int dx = x + walk[i][0], dy = y + walk[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || vis[dx][dy] || map[dx][dy] == '#') continue;
if (is_tp(map[dx][dy]))
{
int tx, ty;
int temp = (int)map[dx][dy];
findTpEnd(temp, dx, dy, tx, ty);
if (cnt[temp] == 2)
{
vis[dx][dy] = true;
Q.push({tx, ty, step + 1});
vis[dx][dy] = false;
} else {
Q.push({dx, dy, step + 1});
vis[dx][dy] = false;
}
} else {
Q.push({dx, dy, step + 1});
vis[dx][dy] = false;
}
}
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> map[i][j];
if (is_tp(map[i][j]))
{
int temp = map[i][j];
tpGate[temp][cnt[temp]].x = i;
tpGate[temp][cnt[temp]].y = j;
cnt[temp]++;
}
if (map[i][j] == '@')
{
sx = i, sy = j;
}
}
}
BFS();
printf("%d", ans);
return 0;
}
稍微用点脑子,明显的两个问题
- 回溯语句没删,合着BFS也回溯是吧
- 递归的思想直接照搬,剪枝那些也得删。
处理完之后TLE,没办法,不能偷懒,重写BFS。
这次学聪明了,不在for枚举坐标的时候特判传送门,而是枚举前直接特判传送门,如果是的话直接把当前操作的队列点改为传送后的队列点,一下省了一堆特判。
搞了三个半小时,终于AC。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
struct coord {
int x, y;
};
struct status {
int x, y, step;
};
int walk[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, sx, sy, ans = 0x7fffffff;
char map[301][301];
coord tpGate[130][2];
queue<status> Q;
int cnt[130];
bool vis[301][301];
bool is_tp(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
void findTpEnd(int ch, int x, int y,int& dx, int& dy)
{
if (tpGate[ch][0].x == x && tpGate[ch][0].y == y)
{
dx = tpGate[ch][1].x, dy = tpGate[ch][1].y;
return ;
}
else
{
dx = tpGate[ch][0].x, dy = tpGate[ch][0].y;
return ;
}
}
void BFS()
{
Q.push({sx, sy, 0});
while(!Q.empty())
{
status node = Q.front();
Q.pop();
int x = node.x, y = node.y, step = node.step;
if (map[x][y] == '=')
{
ans = step;
return ;
}
if (is_tp(map[x][y]))
{
findTpEnd(map[x][y], x, y, x, y);
}
for (int i = 0; i < 4; i++)
{
int dx = x + walk[i][0], dy = y + walk[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || vis[dx][dy] || map[dx][dy] == '#') continue;
vis[dx][dy] = true;
Q.push({dx, dy, step + 1});
}
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> map[i][j];
if (is_tp(map[i][j]))
{
int temp = map[i][j];
tpGate[temp][cnt[temp]].x = i;
tpGate[temp][cnt[temp]].y = j;
cnt[temp]++;
}
if (map[i][j] == '@')
{
sx = i, sy = j;
}
}
}
BFS();
printf("%d", ans);
return 0;
}