题目思路:由于飞行的时候只计算变身的时间而不算飞行的时间,也就是说,走一步和飞一次(无论飞多久)花费的时间是一样的,因此,我们可以用广搜来解决这个问题。无论是飞行还是步行,都可以作为一个节点放到bfs状态的队列之中。
状态我用了一个结构体,内有主角的坐标位置、当前花销时间、可飞行的距离。既然是遍历,就要记着已经遍历过的位置,这里的visited数组有点特别,是一个三位数组,第一、二维分别表示坐标位置,第三维表示当前剩余能够飞行的距离。一开始我的visited数组只有两维,而在考虑飞行和步行的优先关系时,认为如果在同一时间,用飞的和用步行的都能到达某一个位置,那么步行肯定是比飞行优越的,所以在飞行到某个位置的时候,我就没有将visited数组相应的位置置为true,这就一直wa了。后来我重新考虑了飞行和步行的关系,认为,上述的情况下,的确步行是优越于飞行的,但是我没有考虑飞行和飞行之间的关系。如果首先可以飞行到位置A,飞行的距离比较长,将主角的能量都用完了。但如果主角可以从B点飞行较短的距离,也可以到达A点,但visited已经置为true了,就不能飞过去了,但如果能飞过去,而且下一步能够很快地飞到终点,那么算出来的结果一定是错的。
先上带有bug的代码。
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct Node{
Node(int a, int b, int l, int t){
x = a;
y = b;
left = l;
time = t;
}
int x;
int y;
int left;
int time;
};
int dir[][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int m, n, d;
bool visited[101][101];
char matrix[101][101];
bool isValid(int x, int y){
return x >= 1 && x <= m && y >= 1 && y <= n;
}
int main(){
cin >> m >> n >> d;
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
cin >> matrix[i][j];
}
}
/* for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
cout << matrix[i][j];
}
cout << endl;
}
*/
int result = 0;
queue<Node> q;
q.push(Node(1, 1, d, 0));
memset(visited,false, sizeof(visited));
visited[1][1] = true;
while(!q.empty()){
Node cur = q.front();
q.pop();
int tempx, tempy;
for(int i = 0; i < 4; ++i){
tempx = cur.x + dir[i][0];
tempy = cur.y + dir[i][1];
if(isValid(tempx, tempy)){
if(!visited[tempx][tempy] && matrix[tempx][tempy] == 'P'){
if(tempx == m && tempy == n){
result = cur.time + 1;
break;
}
q.push(Node(tempx, tempy, cur.left, cur.time+1));
visited[tempx][tempy] = true;
}
}
else
continue;
for(int j = 2; j <= cur.left; ++j){
tempx = cur.x + j*dir[i][0];
tempy = cur.y + j*dir[i][1];
if(isValid(tempx, tempy) && !visited[tempx][tempy] && matrix[tempx][tempy] == 'P'){
if(tempx == m && tempy == n){
result = cur.time + 1;
break;
}
q.push(Node(tempx, tempy, cur.left-j, cur.time+1));
}
}
if(result != 0)
break;
}
if(result != 0)
break;
}
if(result != 0)
cout << result << endl;
else
cout << "impossible" << endl;
}
再上正确的代码:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct Node{
Node(int a, int b, int l, int t){
x = a;
y = b;
left = l;
time = t;
}
int x;
int y;
int left;
int time;
};
int dir[][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int m, n, d;
bool visited[101][101][101];
char matrix[101][101];
bool isValid(int x, int y){
return x >= 1 && x <= m && y >= 1 && y <= n;
}
int main(){
cin >> m >> n >> d;
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
cin >> matrix[i][j];
}
}
/* for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
cout << matrix[i][j];
}
cout << endl;
}
*/
int flag = false;
queue<Node> q;
q.push(Node(1, 1, d, 0));
memset(visited,false, sizeof(visited));
visited[1][1][d] = true;
while(!q.empty()){
Node cur = q.front();
if(cur.x == m && cur.y == n){
cout << cur.time << endl;
flag = true;
break;
}
q.pop();
int tempx, tempy;
for(int i = 0; i < 4; ++i){
tempx = cur.x + dir[i][0];
tempy = cur.y + dir[i][1];
if(isValid(tempx, tempy)){
if(!visited[tempx][tempy][cur.left] && matrix[tempx][tempy] == 'P'){
q.push(Node(tempx, tempy, cur.left, cur.time+1));
visited[tempx][tempy][cur.left] = true;
}
}
else
continue;
for(int j = 2; j <= cur.left; ++j){
tempx = cur.x + j*dir[i][0];
tempy = cur.y + j*dir[i][1];
if(isValid(tempx, tempy) && !visited[tempx][tempy][cur.left-j] && matrix[tempx][tempy] == 'P'){
q.push(Node(tempx, tempy, cur.left-j, cur.time+1));
visited[tempx][tempy][cur.left-j] = true;
}
}
}
}
if(!flag)
cout << "impossible" << endl;
}
如果给visited数组加多一维的话就可以解决这个问题。
这个题目给我的思考是:考虑问题时,需要将变量的多种情况进行匹配考虑,而不能只考虑部分的配对情况,比较类似于测试的黑盒level2的组合配对。