1定义
名称 | 意义 |
i | 石块在数组stones中的下标 |
position[i] | 第i个石块的position,即stones[i] |
max_last_step[i] | 到达第i个石块的最后一步所有可能的步长的最大值 |
2初始状态分析
由于position =1的下一跳position只能是2,3, 因此若可达,两者必有一个有石块,因此初始状态为以下三个状态之一:
(1) 若position = 2, position = 3都有石块,则状态为:
i | 1 | 2 | 3 |
position[i] | 1 | 2 | 3 |
max_last_step[i] | 1 | 1 | 2 |
(2) 若position = 2有石块,position =3没有石块,则状态为:
i | 1 | 2 |
position[i] | 1 | 2 |
max_last_step[i] | 1 | 1 |
(3) 若position = 2没有石块,position =3有石块,则状态为:
i | 1 | 2 |
position[i] | 1 | 3 |
max_last_step[i] | 1 | 2 |
3三个推论
4算法描述
广度优先遍历每个石块。
使用一个二维数组visited记录遍历到的每个石块在数组stones中的下标和上一跳的步长。由推论一,这个二维数组的每个维度的长度都不超过stones数组的长度。
5优化
由推论三,若最后一个石块可达,则stones数组必须满足:
因此,可以先对stones数组遍历一遍,判断该必要条件是否满足。
6算法实现
具体实现中,为了减少减法运算,把二维数组visited中的上一跳步长改为了下一跳最小步长,即上一跳步长-1
#include <stdbool.h>
#include <stdlib.h>
struct record {
int stone_index;
int min_step;
};
bool binary_search(int *arr, int size, int elem, int *index)
{
int start = 2;
int end = size - 1;
int mid;
while (start <= end)
{
mid = (start + end) >> 1;
if (elem == arr[mid])
{
*index = mid;
return true;
}
if (elem < arr[mid]) end = mid - 1;
else start = mid + 1;
}
*index = start;
return false;
}
bool can_cross(int* stones, int stonesSize, int **visited, struct record *queue)
{
int last_stone = stones[stonesSize - 1];
struct record *curr;
int front = 0;
int tail = 0;
int stone_position;
int stone_index;
bool is_stone;
int curr_min_step;
curr = &queue[tail++];
curr->stone_index = 1;
curr->min_step = 0;
visited[1][0] = 1;
while (front != tail)
{
curr = &queue[front++];
curr_min_step = curr->min_step;
stone_position = stones[curr->stone_index] + curr_min_step;
curr_min_step--;
if (stone_position == last_stone || stone_position + 1 == last_stone ||
stone_position + 2 == last_stone) return true;
is_stone = binary_search(stones, stonesSize, stone_position, &stone_index);
if(is_stone && curr_min_step >= 0 && !visited[stone_index][curr_min_step])
{
curr = &queue[tail++];
curr->stone_index = stone_index;
curr->min_step = curr_min_step;
visited[stone_index][curr_min_step] = 1;
}
stone_position++;
curr_min_step++;
if (stone_index < stonesSize && stones[stone_index] < stone_position)
{
stone_index++;
}
if (stone_index < stonesSize && stones[stone_index] == stone_position && !visited[stone_index][curr_min_step])
{
curr = &queue[tail++];
curr->stone_index = stone_index;
curr->min_step = curr_min_step;
visited[stone_index][curr_min_step] = 1;
}
stone_position++;
curr_min_step++;
if (stone_index < stonesSize && stones[stone_index] < stone_position)
{
stone_index++;
}
if (stone_index < stonesSize && stones[stone_index] == stone_position && !visited[stone_index][curr_min_step])
{
curr = &queue[tail++];
curr->stone_index = stone_index;
curr->min_step = curr_min_step;
visited[stone_index][curr_min_step] = 1;
}
}
return false;
}
bool canCross(int* stones, int stonesSize) {
int **visited;
struct record *queue;
bool res;
int i;
if (stones[1] != 1) return false;
if (stonesSize == 2) return true;
visited = (int **)malloc(sizeof(*visited) * stonesSize);
for (i = 0; i < stonesSize; i++)
{
visited[i] = (int *)malloc(sizeof(*visited[0]) * stonesSize);
memset(visited[i], 0, sizeof(*visited[0]) * stonesSize);
}
queue = (struct record *)malloc(sizeof(*queue) * stonesSize * stonesSize);
res = can_cross(stones, stonesSize, visited, queue);
for (i = 0; i < stonesSize; i++)
{
free(visited[i]);
}
free(visited);
free(queue);
return res;
}