CSP-S 2023 密码锁 题解

题意简述

5 位密码锁,每一位是 0‑9 环形(9 下一个是 0)。锁车操作:从正确密码出发,恰好执行一次操作,操作二选一:

转动某 1 个拨圈任意幅度;

转动一对相邻拨圈,两个拨圈转动幅度完全相同。

现在给出 n 个锁车后的状态(全部不等于正确密码)。求:有多少种 5 位密码,满足:给出的每一个状态,都可以由该密码通过恰好一次合法锁车操作得到。

数据范围:1<=n<=8。

题目分析

由于总密码空间=100000,可以暴力枚举全部候选密码。

核心函数详细解释

cpp 复制代码
bool check(int a[],int b[][5])
{
    // 遍历每一个给出的锁后状态
    for(int i=0;i<n;i++)
    {
        int s=0;
        //统计a(正确密码)与b[i](锁后状态)有多少位不一样
        for(int j=0;j<5;j++)
        {
            if(b[i][j]!=a[j]) s++;
        }
        // s=0:等于原密码,题目说锁后状态不能是正确密码;s>2超过最多改动2位,直接false
        if(s>2||s==0) return 0;

        if(s==1) continue; //只改1位,合法,下一个状态

        // s==2:恰好两位不同,必须是相邻,偏移模10相等
        for(int j=0;j<5;j++)
        {
            if(b[i][j]!=a[j])
            {
                // j位不同,j+1必须也要不同,否则不是相邻两位
                if(b[i][j+1]==a[j+1]) return 0;
                // 计算两个位置的偏移模10,必须相等
                else if((b[i][j]-a[j]+10)%10==(b[i][j+1]-a[j+1]+10)%10)
                {
                    break; //满足条件,退出j循环,该状态合法
                }
                else return 0; //偏移不等,非法
            }
        }
    }
    return true; //n个状态全部校验通过,这是一个合法正确密码
}

注意:j只会找到第一个不一样的下标,要求j与j+1同时不一样,偏移相等,就满足 "相邻两位改动、偏移相同"。

完整AC代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int n,a[6],b[10][5],ans=0;
bool check(int a[],int b[][5])
{
    for(int i=0;i<n;i++)
    {
        int s=0;
        for(int j=0;j<5;j++)
        {
            if(b[i][j]!=a[j]) s++;
        }
        if(s>2||s==0) return 0;
        if(s==1) continue;
        for(int j=0;j<5;j++)
        {
            if(b[i][j]!=a[j])
            {
                if(b[i][j+1]==a[j+1]) return 0;
                else if((b[i][j]-a[j]+10)%10==(b[i][j+1]-a[j+1]+10)%10)
                {
                    break;
                }
                else return 0;
            }
        }
    }
    return true;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=4;j++)
        {
            cin>>b[i][j];
        }
    }
    for(int i=100000;i<=199999;i++)//这里有一个枚举小技巧:如果不想五重循环的话,可以这样做。
    {
        int x=i;
        for(int j=4;j>=0;j--)
        {
            a[j]=x%10;
            x/=10;
        }
        if(check(a,b))
        {
            ans++;
        }
    }
    cout<<ans;
	return 0;
}
相关推荐
OPEN-F1 小时前
C++进阶教程:运算符重载与类型转换
java·c++·算法
牧杉-惊蛰1 小时前
将数组对象根据自定义排列
java·开发语言·算法
inquisiter2 小时前
损失函数在标量和矩阵上的求导对比
线性代数·算法·矩阵
离凌寒2 小时前
一、关于st上制作外部烧录算法时软件识别不到算法文件的问题总结
算法
青 春 记 忆3 小时前
LeetCode 283. 移动零|Python 解法详解
python·算法·leetcode
Hrain-AI4 小时前
企业 AI 治理运营怎么做:分级授权、Token 用量可观测与模型统一纳管
大数据·人工智能·算法
剑指offer.4 小时前
Linux多任务-线程篇
java·jvm·算法
nike0good5 小时前
CF 126B(Password-z algorithm/exkmp)
开发语言·c++·算法