一个m*n的方格纸上,有0、1、2三种数字,可以想像0是面墙,不能通过,1是通道上的一个点,2是储物点,求这个方格纸上每个1的点与离它最近的2之间的距离。(有上下左右四个方向可走。)
比如,一个5*5的格子上有:
0 1 1 0 2
1 0 2 0 1
1 1 0 1 1
0 1 1 1 0
0 1 0 0 0
则每个1到2之间的最短距离为:
N 2 1 N 0
9 N 0 N 1
8 7 N 3 2
N 6 5 4 N
N 7 N N N
用N表示原来的墙,0表示原来的2。
刚看到这题时,很多人都会想从1往2上扫,然后利用之前的结果优化,但怎么利用之前的结果,是个问题。
于是我们需要换一种思路:从2反向找1,一个广搜,是不是就解决了?
好了,不废话,直接贴最终代码了:
#include <stdio.h> // scanf, printf
#include <stdlib.h> // malloc
int _dirs[4][4] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
typedef struct {
int row, col;
} pos;
pos* new_pos(int row, int col) {
pos* p = (pos*)malloc(sizeof(pos));
p->row = row;
p->col = col;
return p;
}
void pos_free(pos* p) {
free(p);
}
typedef struct node {
void* data;
struct node* next;
} node, *queue;
node* new_node(void* data) {
node* n = (node*)malloc(sizeof(node));
n->data = data;
n->next = NULL;
return n;
}
void node_free(node* n) {
free(n);
}
void queue_push(queue* q, node* n) {
n->next = *q;
*q = n;
}
node* queue_pop(queue* q) {
node* n = *q;
*q = n->next;
return n;
}
int queue_empty(queue q) {
return q == NULL;
}
typedef struct {
int** grid; // 方格
int** dist; // 距离
int row, col;
queue twos;
} grid;
int unreach_dist(int row, int col) {
return row + col;
}
grid* new_grid(int row, int col) {
grid* g = (grid*)malloc(sizeof(grid));
g->row = row;
g->col = col;
g->twos = NULL;
g->grid = (int**)malloc((row+2) * sizeof(int*));
for (int r = 0; r <= row+1; r++) {
g->grid[r] = (int*)malloc((col+2) * sizeof(int));
}
for (int r = 0; r <= row+1; r++) {
g->grid[r][0] = 0; // 左竖边为0
g->grid[row+1][0] = 0; // 右竖边为0
g->grid[0][r] = 0; // 上横边为0
g->grid[0][row+1] = 0; // 下横边为0
}
g->dist = (int**)malloc((row+2) * sizeof(int*));
for (int r = 0; r <= row+1; r++) {
g->dist[r] = (int*)malloc((col+2) * sizeof(int));
for (int c = 0; c <= col+1; c++) {
g->dist[r][c] = unreach_dist(row, col);
}
}
return g;
}
void grid_free(grid* g) {
for (int r = 0; r <= g->row+1; r++) {
free(g->dist[r]);
}
free(g->dist);
for (int r = 0; r <= g->row+1; r++) {
free(g->grid[r]);
}
free(g->grid);
// It is callers responsibility to free g->twos.
free(g);
}
grid* read_input() {
int row, col, r, c;
scanf("%d %d", &row, &col);
grid* g = new_grid(row, col);
for (r = 1; r <= row; r++) {
for (c = 1; c <= col; c++) {
scanf("%d", &g->grid[r][c]);
}
}
return g;
}
void find_2_slots(grid* g) {
queue* q = &g->twos;
for (int r = 1; r <= g->row; r++) {
for (int c = 1; c <= g->col; c++) {
if (g->grid[r][c] == 2) {
g->dist[r][c] = 0;
queue_push(q, new_node((void*)new_pos(r, c)));
}
}
}
}
void find_nearest_dist(grid *g) {
while (!queue_empty(g->twos)) {
queue twos = NULL;
while (!queue_empty(g->twos)) {
node* n = queue_pop(&g->twos);
pos* p = (pos*)n->data;
int d = g->dist[p->row][p->col] + 1;
for (int i = 0; i < 4; i++) {
int r = p->row + _dirs[i][0];
int c = p->col + _dirs[i][1];
if (g->grid[r][c]==1 && d<g->dist[r][c]) {
g->dist[r][c] = d;
queue_push(&twos, new_node((void*)new_pos(r, c)));
}
}
pos_free(p);
node_free(n);
}
g->twos = twos;
}
}
void print_dist(grid* g) {
for (int r = 1; r <= g->row; r++) {
for (int c = 1; c <= g->col; c++) {
if (g->dist[r][c] == unreach_dist(g->row, g->col)) {
printf("N ");
} else {
printf("%d ", g->dist[r][c]);
}
}
printf("\n");
}
}
int main(void) {
grid* g = read_input();
find_2_slots(g);
find_nearest_dist(g);
print_dist(g);
grid_free(g);
return 0;
}