描述
骑士在一张 n x n 的棋盘上巡视。在 有效 的巡视方案中,骑士会从棋盘的 左上角 出发,并且访问棋盘上的每个格子 恰好一次 。
给你一个 n x n 的整数矩阵 grid ,由范围 [0, n * n - 1] 内的不同整数组成,其中 grid[row][col] 表示单元格 (row, col) 是骑士访问的第 grid[row][col] 个单元格。骑士的行动是从下标 0 开始的。
如果 grid 表示了骑士的有效巡视方案,返回 true;否则返回 false。
注意,骑士行动时可以垂直移动两个格子且水平移动一个格子,或水平移动两个格子且垂直移动一个格子。下图展示了骑士从某个格子出发可能的八种行动路线。
解题思路
直接模拟法
根据题目每可知骑士移动有八个方向,定义两个方向数组,按顺时针方向从1点钟位置开始分别模拟行和列可能的变化值dx和dy。
int dx[8]={1, 2, 2, 1, -1, -2, -2, -1};
int dy[8]={-2, -1, 1, 2, 2, 1, -1, -2};
骑士会从棋盘的 左上角 出发,并且访问棋盘上的每个格子恰好一次 。
用
if(grid[0][0]!=0)
return false;
来约束骑士从左上角出发。
骑士的行动是从下标 0 开始的,用一个for循环来约束骑士顺序访问,保证每个格子只能访问一次,且下标递增。用一个bool变量flag来判断能否到达i,如果能到达flag置为true。如果本轮无法到达i,那么直接return flase,代表当前位置无法到达i。
for(int i=1; i<len*len; i++)
{
bool flag = false;
//探测是否能到达i,能到达flag置为true
if(!flag)
return false;
}
return true;
nrow为目前所处的行,ncol为目前所处的列。往八个方向进行探测,x,y记录从当前位置可能到达的位置,如果越界直接进入下一轮循环。如果能到达i,那么置flag为true,并将当前位置nrow和ncol更新为探测的x,y。
for(int j=0; j<8; j++)
{
int x = ncol + dx[j];
int y = nrow + dy[j];
if(x<0 || x>=len || y<0 || y>=len)
continue;
if((grid[x][y] == i))
{
flag = true;
ncol = x;
nrow = y;
}
}
完整代码如下:
class Solution {
public:
bool checkValidGrid(vector<vector<int>>& grid) {
int nrow=0, ncol=0, n=0;
int dx[8]={1, 2, 2, 1, -1, -2, -2, -1}, dy[8]={-2, -1, 1, 2, 2, 1, -1, -2};
if(grid[0][0]!=0)
return false;
int len = grid.size();
for(int i=1; i<len*len; i++)
{
bool flag = false;
for(int j=0; j<8; j++)
{
int x = ncol + dx[j];
int y = nrow + dy[j];
if(x<0 || x>=len || y<0 || y>=len)
continue;
if((grid[x][y] == i))
{
flag = true;
ncol = x;
nrow = y;
}
}
if(!flag)
return false;
}
return true;
}
};