现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。
输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数
输入例子1:
1,2
输出例子1:
65
例子说明1:
输入m=1,n=2,表示最少1个键,最多2个键,符合要求的键数是1个键和2个键,其中1个键的有效模式有9种,两个键的有效模式有56种,所以最终有效模式总数是9+56=65种,最终输出65。
class Solution {
public:
/**
* 实现方案
* @param m int整型 最少m个键
* @param n int整型 最多n个键
* @return int整型
*/
void move(vector<vector<int> >& board, int i, int j, int k, int m, int n, int& ans){
// 如果已经走过的点数大于等于m,则是有效路径,ans++
if(k >= m) ans ++;
// 如果已经走过的点数等于n,则不需要继续探索,故返回
if(k == n) return;
// 如果已经走过的点数小于n,则还可以继续探索
for(int dx=-2; dx<=2; dx++){
for(int dy=-2; dy<=2; dy++){
// i+dx>=0 && i+dx<=2 && j+dy>=0 && j+dy<=2是3x3格子的边界条件
// board[i+dx][j+dy]==0则表明该位置未曾经过
if(i+dx>=0 && i+dx<=2 && j+dy>=0 && j+dy<=2 && board[i+dx][j+dy]==0){
// 如果两点之间没有第三个点(条件:dx%2 || dy%2),则无需判断是否经过“已经过”的点
// 如果两点之间有第三个点,则需要判断这个点是否是已经走过的点
// dx%2 == 0则表示横跨2步,dy%2 == 0 表示竖跨2步
// 而当dx%2 || dy%2成立时,表明横向跨1步,或者纵向跨1步,一旦只跨1步则不存在中间点了,可以画图结合理解
// (!(dx%2) && !(dy%2) && board[i+dx/2][j+dy/2]==1) 成立时,表明横跨2步,纵跨2步,并且横跨1纵跨1的点(即中点)已经走过(因为1表示走过)
if(dx%2 || dy%2 || (!(dx%2) && !(dy%2) && board[i+dx/2][j+dy/2]==1)){
board[i+dx][j+dy] = 1;
move(board, i+dx, j+dy, k+1, m, n, ans);
board[i+dx][j+dy] = 0;
}
}
}
}
return;
}
int solution(int m, int n) {
// write code here
vector<vector<int> > board(3, vector<int>(3, 0));
int ans = 0;
// 如果n等于0,则直接返回0
if(n == 0) return ans;
// 选择棋盘上任意一点作为起点
for(int i=0; i<3; i++){
for(int j=0; j<3; j++){
board[i][j] = 1;
move(board, i, j, 1, m, n, ans);
board[i][j] = 0;
}
}
return ans;
}
};