题意:
房间里起火,人和火可以上下左右走,每分钟都走一格(火是四个方向同时一格),都不能越过墙。人只要走到房间边界(非墙)就可以逃生。给定人、火、墙的位置,如果人能逃生,输出所需时间,如果不能,输出IMPOSSIBLE
思路:
对于每个可走格子,算火的最短到达时间和人的最短到达时间,“最短”用BFS达成,先火BFS后人BFS
火的BFS中,由于在每分钟时间内,所有的火都同时扩散,参考《文明》,vector结合queue
在人的BFS中,如果人的下一格子<那个格子的火则可走
原本是全部算完之后再遍历边界,但问题在于算人的时候没有考虑到火已经先到的问题
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
struct node {
int x, y;
};
struct Time {
int F, J;
};
queue<node> fq;
queue<node> jq;
int m, n;
Time dis[1000 + 10][1000 + 10];
int map[1000 + 10][1000 + 10];
vector<node> v;
void Clear() {//dis初始化
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dis[i][j].F = -1;
dis[i][j].J = -1;
}
}
}
int dx[] = { 0,-1,1,0,0 };
int dy[] = { 0,0,0,-1,1 };
//上下左右
void FireBFS() {
for(int i=0;i<v.size();i++) fq.push(v[i]);
v.clear();
while (!fq.empty()) {
node t = fq.front();
fq.pop();
for (int i = 1; i <= 4; i++) {
int nx = t.x + dx[i];
int ny = t.y + dy[i];
if (nx<1 || ny<1 || nx>m || ny>n || map[nx][ny] == -1 || dis[nx][ny].F != -1) continue;
dis[nx][ny].F = dis[t.x][t.y].F + 1;
node p;
p.x = nx; p.y = ny;
v.push_back(p);
}
}
}
int JoeBFS() {
while (!jq.empty()) {
node t = jq.front();
jq.pop();
if(t.x==m||t.x==1||t.y==1||t.y==n) return dis[t.x][t.y].J+1;
for (int i = 1; i <= 4; i++) {
int nx = t.x + dx[i];
int ny = t.y + dy[i];
//越界或者是墙
if (nx<1 || ny<1 || nx>m || ny>n || map[nx][ny] == -1) continue;
//已经走过
if(dis[nx][ny].J != -1) continue;
//火已经到了
if(dis[nx][ny].F!=-1&&dis[nx][ny].F<=dis[t.x][t.y].J + 1)continue;
dis[nx][ny].J = dis[t.x][t.y].J + 1;
node p;
p.x=nx;p.y=ny;
jq.push(p);
}
}
return -1;
}
int main()
{
int t;
cin >> t;
while (t--) {
while (!fq.empty()) fq.pop();
while (!jq.empty()) jq.pop();
cin >> m >> n;
node t;
Clear();
v.clear();
for (int i = 1; i <= m; i++) {
char c = getchar();
for (int j = 1; j <= n; j++) {
c = getchar();
if (c == '#') map[i][j] = -1;
else if (c == 'F') {
map[i][j] = -2;
dis[i][j].F = 0;
t.x = i; t.y = j;
v.push_back(t);
}
else if (c == 'J') {
map[i][j] = 1;
dis[i][j].J = 0;
t.x = i; t.y = j;
jq.push(t);
}
else map[i][j] = 0;
}
}
while(v.size()) FireBFS();
int ans=JoeBFS();
if (ans==-1) cout << "IMPOSSIBLE" << endl;
else cout << ans << endl;
}
return 0;
}
!!!!错误代码!!!!
思路是人和火都一步一步走,走法参考《文明》
能过样例,但是WA,原因是忘记倒空队列和vector
但还是TLE了
而且也没考虑多个出口时取最短时间
走出去的边界也没考虑全(忽略了上边和左边)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
int m, n;
char map[1000 + 10][1000 + 10];
int dis[1000 + 10][1000 + 10];
struct node {
int x, y;
};
queue<node> Fq;
queue<node> Jq;
int dx[] = { 0,1,-1,0,0 };
int dy[] = { 0,0,0,1,-1 };
//下,上,右,左
vector<node> Fv;
vector<node> Jv;
int bfs() {
for(int i=0;i<Fv.size();i++) Fq.push(Fv[i]);
Fv.clear();
for(int i=0;i<Jv.size();i++) Jq.push(Jv[i]);
Jv.clear();
//先火后人
node k;
while(!Fq.empty()){
node F = Fq.front();
Fq.pop();
for (int i = 1; i <= 4; i++) {
int fx = F.x + dx[i];
int fy = F.y + dy[i];
if (fx<1 || fy<1 || fx>m || fy>n || dis[fx][fy] == -1 || dis[fx][fy] == -2) continue;
dis[fx][fy] = -2;
k.x = fx;
k.y = fy;
Fv.push_back(k);
}
}
node J = Jq.front();
Jq.pop();
if ((J.x == m || J.y == n) && dis[J.x][J.y] != -1) return -1;//走出去了
for (int i = 1; i <= 4; i++) {
int jx = J.x + dx[i];
int jy = J.y + dy[i];
if (jx<1 || jy<1 || jx>m || jy>n || dis[jx][jy] != 0) continue;
k.x = jx;
k.y = jy;
Jv.push_back(k);
}
if (Jv.size()) return 1;//有路可走
else return 0;//无路可走
}
int main()
{
int t;
cin >> t;
while (t--) {
memset(dis, 0, sizeof(dis));
Fv.clear();
Jv.clear();
while(!Jq.empty()) Jq.pop();
while(!Fq.empty()) Fq.pop();
cin >> m >> n;
for (int i = 1; i <= m; i++) {
char c = getchar();
for (int j = 1; j <= n; j++) {
c = getchar();
map[i][j]=c;
node k;
if (c == '#') dis[i][j] = -1;
else if (c == 'J') {
dis[i][j] = 1;
k.x = i;
k.y = j;
Jv.push_back(k);
}
else if (c == 'F') {
dis[i][j] = -2;
k.x = i;
k.y = j;
Fv.push_back(k);
}
else dis[i][j] = 0;
}
}
/* cout<<endl;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++) cout<<map[i][j];
cout<<endl;
}
*/
int Result;
int i;
for (i = 1;;i++) {
Result = bfs();
if (Result==1) continue;
else break;
}
if (!Result) cout << "IMPOSSIBLE" << endl;
else cout << i << endl;
}
return 0;
}