密码锁--题解
[CSP-S 2023]密码锁 - 题解
题目大意
题目描述了一个密码锁的情景,密码锁由五个拨圈组成,每个拨圈上有从
题目分析
这道题的关键是要找出所有可能的正确密码,使得每个正确密码都能通过给定的锁车方式生成
部分分解法(骗分解法)
以下是原题的测试点范围:
| 测试点 | 特殊性质 | |
|---|---|---|
| 无 | ||
| 无 | ||
| A | ||
| 无 |
特殊性质 A:保证所有正确密码都可以通过仅转动一个拨圈得到测试数据给出的
30pts解法
测试数据第一组:81即可。
#include<bits/stdc++.h>
#define N 11
using namespace std;
int n;
int main(){
scanf("%d",&n);
printf("81");
return 0;
}
60pts解法
在
所以我们可以分情况讨论,代码如下:
#include<bits/stdc++.h>
#define N 11
using namespace std;
int n;
int main(){
scanf("%d",&n);
if(n==1){
printf("81");
}
else{
printf("%d",10-n);
}
return 0;
}
短短几行拿下
正解思路
- 遍历所有可能的
5 个拨圈的数字组合,这里我们可以使用5 个嵌套的循循环,每个循环从0 到9 ,代表每个拨圈的数字。 - 对于每种组合,遍历
n 个状态,检查是否满足通过给定的锁车方式生成这n 个状态。这里我们定义一个函数check来判断是否满足条件。 - 在
check函数中,我们首先统计每个拨圈需要改变的数字的个数,如果个数为1 ,说明只需要转动一个拨圈;如果个数为2 ,说明需要同时转动两个相邻的拨圈。我们可以通过计算每个拨圈对应数字的差值来判断是否可以通过同时转动两个相邻拨圈来达到目标状态。 - 如果
check函数返回true,说明这种组合是一个可能的正确密码,增加答案的计数。 - 最后输出答案即可。
AC代码
#include<bits/stdc++.h>
#define N 11
using namespace std;
int n, a[N][N], b[N], ans;
// 检查是否通过锁车方式生成给定状态
bool check(int i) {
int cnt = 0;
for (int j = 1; j <= 5; j++) {
cnt += (a[i][j] != b[j]);
}
// 如果只有一个数字不同,可以通过转动一个拨圈达到目标状态
if (cnt == 1) return true;
// 如果数字不同的个数不是1也不是2,不满足条件
else if (cnt != 2) return false;
// 如果有两个数字不同,检查是否可以通过同时转动两个相邻拨圈达到目标状态
for (int j = 1; j < 5; j++) {
// 分别判断拨动前当前状态和正确密码是否相同并且拨动后两密码是否可以相同
if (a[i][j] != b[j] && a[i][j + 1] != b[j + 1] && (b[j] - a[i][j] + 10) % 10 == (b[j + 1] - a[i][j + 1] + 10) % 10) {
return true;
}
}
return false;
}
// 检查是否所有n个状态都满足条件
bool checkmain() {
for (int i = 1; i <= n; i++) {
if (!check(i)) return false;
}
return true;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 5; j++) {
cin >> a[i][j];
}
}
// 暴力枚举5个数字
for (int i = 0; i <= 9; i++) {
for (int j = 0; j <= 9; j++) {
for (int k = 0; k <= 9; k++) {
for (int l = 0; l <= 9; l++) {
for (int o = 0; o <= 9; o++) {
int num = 0; // 使用数组存储当前枚举的5位数
b[++num] = i;
b[++num] = j;
b[++num] = k;
b[++num] = l;
b[++num] = o;
// 如果满足条件,增加正确密码的个数
if (checkmain()) {
ans++;
}
}
}
}
}
}
cout << ans;
return 0;
}
时间复杂度分析
在主循环中,我们有
空间复杂度分析
- 除了输入数据和输出数据外,主要使用了两个数组
a和b,以及一个整数ans。这三个的空间复杂度是O(n) + O(5) + O(1) = O(n) 。 - 递归调用时会有一定的栈空间占用,但在这里递归的深度不会太大,因此不会显著影响总体空间复杂度。
- 综合考虑,总体空间复杂度为
O(n) 。