菜鸡看到这个题目后,想法很多,实现感觉挺复杂。。网上找的C++的实现都不太靠谱。看到一篇java实现的感觉逻辑清晰,为他点个赞,稍微改下C++。
**> 题目
现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多
n个键可以解锁该屏幕的所有有效模式总数。 其中有效模式是指: 1、每个模式必须连接至少m个键和最多n个键; 2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。**
输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数
原文:JAVA实现
改变上主要是数组定义,已经数组需要初始化;(不赋0初始化总是出错,有专业同学解释下吗)
#include<iostream>
using namespace std;
class Solution {
public:
//用来存储两个键相连经过其他键情况
//vector<vector<int>>arr=
int(*arr)[10]=new int [10][10];
//动态初始化boolean数组 默认值为false
bool *select=new bool [10];
int solution(int m, int n) {
for (int i = 0; i <= 9; i++)
{
select[i] = false;
for (int j = 0; j <= 9; j++)
{
arr[i][j] = 0;
}
}
//三行 1和3连线必须2已经连入
arr[1][3] = arr[3][1] = 2;
arr[4][6] = arr[6][4] = 5;
arr[7][9] = arr[9][7] = 8;
//三竖
arr[1][7] = arr[7][1] = 4;
arr[2][8] = arr[8][2] = 5;
arr[9][3] = arr[3][9] = 6;
//两条对角线
arr[1][9] = arr[9][1] = 5;
arr[3][7] = arr[7][3] = 5;
//用于判断是否可以可以连入 二位数组 int默认值为0 没有跨节点下标为0就是true
select[0] = true;
if (m < 0 || n < m) {
return 0;
}
// 1 3 7 9情况合并 2 4 6 8情况合并 5一种情况
int total = 4 * calculateCount(m, n, 1, 1) + 4 * calculateCount(m, n, 2, 1)
+ calculateCount(m, n, 5, 1);
return total;
}
int calculateCount(int min, int max, int start, int len) {
int count = 0;
if (len > max) {
return 0;
}
if (len >= min) {
count++;
}//这里意味着连接到当前点且深度满足要求时计数+1;在进入本次判定前其实已经判定了不存在跨越连接的情况,所以我觉得其实可以将这几次判断合并,这里这样做的原因主要是递归后便于区分“能不能连(不存在13式的跨越)”和“有没有必要连(只求1步和两步的连法)”
select[start] = true;
for (int i = 1; i < 10; i++) {
//当前节点start没有被选人 并且开始节点start到当前节点i不是跨节点连接
if (!select[i] && select[arr[start][i]]) {
count = count + calculateCount(min, max, i, len + 1);
}
}
select[start] = false;
return count;
}
};
int main() {
Solution test;
cout << test.solution(1, 2) << endl;
system("pause");
return 0;
}