洛谷:P9752
OJ:P5959
这个代码的主要目标是计算出有多少种可能的正确密码,能够通过小 Y 所采用的锁车方式生成输入给出的所有锁车后的密码状态。下面是对代码的详细分析和逻辑解释:
n
:表示锁车后的状态数。ans
:表示符合条件的正确密码的数量。ripwd[5]
:存储当前遍历到的密码组合。wrpwd
:用于存储输入的所有锁车后的状态,大小为 n×5
,其中每一行包含一个密码状态。cnt
:用于存储当前密码和某一个锁车后的密码状态的不同位置。check()
函数这个函数用于判断当前遍历到的 ripwd
密码是否能够通过小 Y 的锁车规则生成所有的锁车状态。具体逻辑如下:
wrpwd[i]
,通过对比每一个拨圈的位置来计算当前密码 ripwd
与锁车状态 wrpwd[i]
的差异。wrpwd[i]
只有一位数字不同,则这个状态可以合法生成,不需要再进一步判断。(ripwd[x]-wrpwd[i][x]+10)%10
来处理圆形拨圈的性质)。如果两个拨圈的转动幅度不一致,则返回 false
。false
。true
。dfs()
函数该函数用于遍历所有的可能密码组合。由于密码锁的每个拨圈都有10个数字,因此总共有 10^5
种可能的密码组合。代码通过深度优先搜索(DFS)遍历所有组合,并通过 check()
函数来判断每一个组合是否符合条件。具体步骤为:
0
到 9
尝试每一个数字,并将其存入 ripwd
数组中。check()
函数判断当前组合是否能生成所有的锁车状态。ans
加 1,表示找到了一个符合条件的密码组合。main()
n
和状态数组 wrpwd
。dfs()
函数,遍历所有可能的正确密码组合。ans
。该程序的主要逻辑是通过递归遍历所有可能的密码组合,并使用 check()
函数检查当前密码是否符合小 Y 的锁车规则。根据题意,锁车规则要求每次锁车时,最多只有一个拨圈被转动,或者相邻的两个拨圈被相同幅度地转动。通过深度优先搜索和对每个密码状态的详细检查,程序可以确定有多少种可能的正确密码。
由于密码锁的每一位有 10 种可能,总共有 10^5
种密码组合。程序使用递归枚举了所有的密码组合,并且每次检查时需要遍历所有的状态。因此时间复杂度大致为 O(10^5 * n)
,其中 n
是锁车后的状态数。在实际中,这样的复杂度应该可以接受。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | /**************************************************************** * Description: 2023_CSP_S_复赛第一题 * Author: Alex Li * Date: 2024-07-11 13:01:49 * LastEditTime: 2024-07-15 17:45:11 ****************************************************************/ #include <iostream> #include <vector> using namespace std; const int N=10; vector< vector<int> > wrpwd;//动态数组,存n种状态 int n,ans,ripwd[5]; //n是有几种状态,ans是结果,ripwd[5]可行的密码组合 bool check(){ for(int i=0;i<n;i++){ vector<int> cnt; //统计对应位数字不同的位置 for(int j=0;j<5;j++) if(ripwd[j]!=wrpwd[i][j])cnt.push_back(j); if(cnt.empty()||cnt.size()>2) return false; //不同只能是1位或都2位,其它都不可能。 //如果只有一位不同,肯定可以匹配,所以不做判断。 //如果有两位不同需要判断 if(cnt.size()==2){ int x=cnt[0], y=cnt[1]; if(x+1!=y&&y+1!=x) return false; int dx=(ripwd[x]-wrpwd[i][x]+10)%10;//因为锁是圆形,需要需要把差值取模 int dy=(ripwd[y]-wrpwd[i][y]+10)%10; if(dx!=dy)return false; //如果两个位置转动位移不同,不是有效密码 } } // for(int i=0;i<5;i++)cout<<ripwd[i]<<' '; //输出密码 // cout<<'\n'; return true; } //遍历所有的密码可能行,总共有10^5种 void dfs(int dep){ if(dep>=5){ if(check())ans++; //对每种密码组合用check函数做检测 return; } for(int i=0;i<=9;i++){ ripwd[dep]=i; dfs(dep+1); } } int main(){ cin>>n; wrpwd.resize(n,vector<int>(5)); //动态数组初始化。 //读入n种状态 for(int i=0;i<n;i++){ for(int j=0;j<5;j++){ cin>>wrpwd[i][j]; } } //cout<<'\n'; //搜索所有的可能密码组合 dfs(0); cout<<ans<<endl; } /*---------------------------------------------------------------- 1 0 0 1 1 5 81 2 2 8 3 5 5 2 8 3 5 1 10 2 0 3 7 3 8 0 3 6 7 8 6 */ |