题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1325
题意:给定 N×M 的矩阵,给定起点和终点。其中矩阵中,0表示墙,1表示可以走的点,2表示脏的点。每次从1走到2或者从2走到1都需要换一次鞋。每次走为八方向。求从起点到终点的换鞋次数最少的最短路是多少。输出最少换鞋次数和最短路。
思路:直接BFS,每次记录到点 (x,y) 的路径和换鞋次数。由于比较级为2个,所以采取优先队列,以换鞋次数为第一比较级,路径长度为第二比较级。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 5e2 + 10;
const int INF = 1e6 + 10;
struct Node {
int x, y;
int path, change;
friend bool operator < (Node a, Node b) {
if (a.change != b.change)
return a.change > b.change;
return a.path > b.path;
}
bool equal(Node b) {
if (this -> x == b.x && this -> y == b.y)
return true;
return false;
}
};
int n, m;
char _map[N][N];
Node dis[N][N]; // 不可使用vis标记数组来标记走过的点不走
int minpath, minchange;
int x[8] = {1, 0, -1, 0, 1, 1, -1, -1};
int y[8] = {0, 1, 0, -1, 1, -1, 1, -1};
bool bfs(Node s, Node e) {
priority_queue<Node> q;
q.push(s);
dis[s.x][s.y] = s;
while (!q.empty()) {
Node now = q.top();
q.pop();
if (now.equal(e)) {
minpath = now.path;
minchange = now.change;
return true;
}
for (int i = 0; i < 8; i++) {
Node to;
to.x = now.x + x[i];
to.y = now.y + y[i];
if (to.x >= 0 && to.x < n && to.y >= 0 && to.y < m
&& _map[to.x][to.y] != '0') {
to.path = now.path + 1;
to.change = now.change;
if (_map[now.x][now.y] != _map[to.x][to.y])
to.change++;
if (dis[to.x][to.y].change > to.change
|| (dis[to.x][to.y].change == to.change && dis[to.x][to.y].path > to.path)) {
q.push(to);
dis[to.x][to.y] = to;
}
}
}
}
return false;
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
Node st, ed;
scanf("%d%d%d%d", &st.x, &st.y, &ed.x, &ed.y);
st.x--, st.y--, ed.x--, ed.y--;
for (int i = 0; i < n; i++)
scanf("%s", _map[i]);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dis[i][j].change = INF;
dis[i][j].path = INF;
}
}
st.path = 1;
st.change = 0;
if (bfs(st, ed))
printf("%d %d\n", minpath, minchange);
else
printf("0 0\n");
}
return 0;
}