错误版本
本题可以理解为矩阵上的单源最短路径,因为数据不是很大,我们可以使用BFS进行搜索PLMM和猫到达图中所有点的最短路径。但是题目加上了附属条件,PLMM走的步数是有限的,而且猫的嗅觉也是有限的。所以我们可以求完最短路径之后,找到一个可以同时满足两个要求的点,如果可以找到,则更新答案。不能则输出-1。
bug样例:
5 3
1 2
P..
.*.
*..
M..
...
(感谢大佬补充数据)
#include <bits/stdc++.h>
using namespace std;
int n, m;
int r, l;
bool vis[2000][2000];
int ans = 0;
char mp[2000][2000];
int sum[2000][2000];
int dp[4][2] = {1, 0, 0, 1, 0, -1, -1, 0};
struct pii
{
int x, y;
} s, e;
void bfs()
{
sum[s.x][s.y] = 0;
queue<pii> p;
p.push(s);
while (p.size())
{
pii q = p.front();
p.pop();
for (int i = 0; i < 4; i++)
{
int x = q.x + dp[i][0], y = q.y + dp[i][1];
if (x < 0 || y < 0 || x >= n || y >= m)
continue;
if (mp[x][y] == '*')
continue;
sum[x][y] = min(sum[x][y], sum[q.x][q.y] + 1);
if (!vis[x][y])
{
vis[x][y] = true;
p.push({x, y});
}
}
}
}
int main(void)
{
cin >> n >> m;
cin >> l >> r;
memset(sum, 0x3f, sizeof sum);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> mp[i][j];
//寻找起始点和终点
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
if (mp[i][j] == 'M')
e.x = i, e.y = j;
if (mp[i][j] == 'P')
s.x = i, s.y = j;
}
//求最短路径
bfs();
int flag = 0;
if (sum[e.x][e.y] >= 0x3f3f3f3f)
{
cout << -1 << endl;
return 0;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
if (sum[i][j] < 0x3f3f3f3f)
{
//寻找满足r1,r2的要求的点
int ll = sum[i][j];
int rr = abs(i - e.x) + abs(j - e.y);
if (ll <= l && rr <= r)
{
cout << sum[e.x][e.y] << endl;
return 0;
}
}
}
cout << -1 << endl;
}
正确版本
将上面的代码在bfs一遍小猫的路径,然后将满足条件的点当做中转站,不断更新答案就可以
ans = min(ans, sum[i][j] + sum1[i][j]);
AC代码
#include <bits/stdc++.h>
using namespace std;
int n, m;
int r, l;
bool vis[2000][2000];
int ans = 0;
char mp[2000][2000];
int sum[2000][2000];
int dp[4][2] = {1, 0, 0, 1, 0, -1, -1, 0};
struct pii
{
int x, y;
} s, e;
void bfs()
{
sum[s.x][s.y] = 0;
queue<pii> p;
p.push(s);
while (p.size())
{
pii q = p.front();
p.pop();
for (int i = 0; i < 4; i++)
{
int x = q.x + dp[i][0], y = q.y + dp[i][1];
if (x < 0 || y < 0 || x >= n || y >= m)
continue;
if (mp[x][y] == '*')
continue;
sum[x][y] = min(sum[x][y], sum[q.x][q.y] + 1);
if (!vis[x][y])
{
vis[x][y] = true;
p.push({x, y});
}
}
}
}
int sum1[2000][2000];
void bfs1()
{
sum1[e.x][e.y] = 0;
queue<pii> p;
p.push(e);
while (p.size())
{
pii q = p.front();
p.pop();
for (int i = 0; i < 4; i++)
{
int x = q.x + dp[i][0], y = q.y + dp[i][1];
if (x < 0 || y < 0 || x >= n || y >= m)
continue;
if (mp[x][y] == '*')
continue;
sum1[x][y] = min(sum1[x][y], sum1[q.x][q.y] + 1);
if (!vis[x][y])
{
vis[x][y] = true;
p.push({x, y});
}
}
}
}
int main(void)
{
cin >> n >> m;
cin >> l >> r;
memset(sum, 0x3f, sizeof sum);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> mp[i][j];
//寻找起始点和终点
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
if (mp[i][j] == 'M')
e.x = i, e.y = j;
if (mp[i][j] == 'P')
s.x = i, s.y = j;
}
//求最短路径
//PLMM到图中的最短路
bfs();
memset(sum1, 0x3f, sizeof sum1);
memset(vis, 0, sizeof vis);
//猫到图中的最短路
bfs1();
int flag = 0;
if (sum[e.x][e.y] >= 0x3f3f3f3f)
{
cout << -1 << endl;
return 0;
}
ans = 0x3f3f3f3f;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
if (sum[i][j] <= 0x3f3f3f3f)
{
//寻找满足r1,r2的要求的点
int ll = sum[i][j];
int rr = abs(i - e.x) + abs(j - e.y);
if (ll <= l && rr <= r)
//答案更新
ans = min(ans, sum[i][j] + sum1[i][j]);
}
}
if (ans >= 0x3f3f3f3f)
cout << -1 << endl;
else
cout << ans << endl;
}