这场PAT甲级的最后一题挺恶心的,题目超级长,对于我这种英语不好的来说简直是折磨!!!那个样例解释着实没看懂
花了近两小时写这一题,最后只过了一个点,当时直接脑袋宕机(加上实在是憋不住了),根本没办法冷静debug了。
躺在床上突然想到,我是直接遍历的整张图找的所有的O点作为起始可行点的,所以:要是里面有一个点不能走到X点,在找最长最短路的时候不久直接成INF了吗,路径也不存在了,那答案。。。。。
越想越气,立马下床重写了代码
整体思路如下:
1. 从X点出发bfs求所有点的最短路,并将能到达的点存下来作为初始可行点,同时记录路径。注意:要求路径是最小的,并且这里求的路径是反着的,所以要求搜索顺序是从大到小,注意是反过来从大到小(0对着2,1对着3,所以搜索顺序应该为:1,0,3,2)。
2. 处理得到的路径,将其反向。
3. 根据题目给出的算法流程,一步一步更新可行点集合,每更新一次就会得到一个路径字符串,直到集合为空,算法结束。
代码如下(样例可过,不知道能不能AC,如果还有错误,还请各位大佬能指出来):
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 110, INF = 0x3f3f3f3f;
int n, m, endx, endy;
char g[N][N];
int dist[N][N];
bool st[N][N];
// 偏移量:上,右,下,左
// 逆向路径,求最大(0-2,1-3)(0123-2301)
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}, fx[4] = {1, 0, 3, 2};
// 可行点集合
set<PII> poss;
// 点到X的路径
map<PII, string> path;
// bfs求最短路
void bfs(int endx, int endy)
{
memset(dist, 0x3f, sizeof dist);
dist[endx][endy] = 0;
st[endx][endy] = true;
queue<PII> q;
q.push({endx, endy});
path[{endx, endy}] = "";
while(q.size()) {
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
int a = t.x + dx[fx[i]], b = t.y + dy[fx[i]];
if(a < 0 || a >= n || b < 0 || b >= m || st[a][b] || g[a][b] == '#') continue;
if(dist[a][b] > dist[t.x][t.y] + 1) {
dist[a][b] = dist[t.x][t.y] + 1;
path[{a, b}] = path[{t.x, t.y}] + (char)('0' + fx[i]);
poss.insert({a, b});
st[a][b] = true;
q.push({a, b});
}
}
}
}
string find_min_path(set<PII> &max_point)
{
string s = "";
for(auto &i : max_point) {
if(s == "" || s > path[i])
s = path[i];
}
return s;
}
// 按照算法流程解决问题
string sol(set<PII> &poss)
{
// 找最长最短路
int max_path_len = 0;
for(auto &i : poss) {
max_path_len = max(max_path_len, dist[i.x][i.y]);
}
// 找最长最短路的所有点
set<PII> max_point;
for(auto &i : poss) {
if(dist[i.x][i.y] == max_path_len)
max_point.insert({i.x, i.y});
}
// 在所有最长最短路点中找到最小路径
string s = find_min_path(max_point);
// 按照最小路径,对所有可行点走一遍,更新可能点
set<PII> temp;
for(auto &i : poss) {
int a = i.x, b = i.y;
for(int i = 0; i < s.size(); i++) {
int ta = a + dx[s[i] - '0'], tb = b + dy[s[i] - '0'];
if(ta < 0 || ta >= n || tb < 0 || tb >= m || g[ta][tb] == '#') break;
else {
a = ta, b = tb;
}
}
if(!temp.count({a, b}) && (a != endx || b != endy)) temp.insert({a, b});
}
poss = temp;
return s;
}
int main()
{
scanf("%d%d", &n, &m);
// 读入地图
for(int i = 0; i < n; i++) scanf("%s", g[i]);
// 找X点
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(g[i][j] == 'X') {
endx = i, endy = j;
}
// bfs求最短路,并求出最短路径,同时记录和X联通的初始点集合
bfs(endx, endy);
// 将求出的路径反向
for(auto &i : path) {
string s = "";
for(int j = i.y.size() - 1; ~j; j--) {
if(i.y[j] == '0') s += '2';
else if(i.y[j] == '1') s += '3';
else if(i.y[j] == '2') s += '0';
else s += '1';
}
i.y = s;
}
string ans = "";
while(poss.size()) {
ans += sol(poss);
}
cout << ans;
return 0;
}
事实证明还是错的,挑不出来啊。。。
一个continue,想成了break,痛失11分。倒数第3个点TLE了。。。
感觉还是有问题吧。。。,要是有不可达的点,那就无法更新可行点集合,不就进死循环了,有大佬能帮忙de下bug吗😭
复现了一下考试时的代码,如果初始O点全加进去,且里面存在不可达点会TLE,但是其他测试点都是WA,难道终究是我读错题了吗