P9752题解
思路
先说句题外话:原来提高组也有签到题!
都说了这是签到题,所以我们只需要纯暴力枚举 的每个密码即可。这里的暴力枚举每个数可以是 DFS 枚举,也可以是直接五重循环枚举。
枚举好了以后,当然要进行判断这个密码是否合法了。是否合法必须满足这几个条件:
- 不能与任意一个锁车后的密码相同。
- 对于每个锁车后的密码,最多只能有 个不同之处。
- 如果这个锁车后的密码和当前枚举到的密码只有一个不同的数字,那枚举到的这个密码对于这个锁车后的密码就是合法的;如果有两个不同的数字,则需要判断,这两个不同的数字位置是否相邻,两个相差的值(需要转动的幅度)是否相同即可。
代码
# include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, a[10][10], sum, b[10], tot, cha, last;
bool compare (int a[], int b[]) { //比较两个数组是否相等
for (int i = 0; i < 5; ++ i)
if (a[i] != b[i])
return 0;
return 1;
}
bool check () {
for (int i = 0; i < n; ++ i)
if (compare (a[i], b)) //如果有相等就不合法
return 0;
for (int i = 0; i < n; ++ i) {
tot = cha = 0; //tot 表示不相等个数,cha 表示需要转动的幅度
for (int j = 0; j < 5; ++ j)
if (a[i][j] != b[j]) { //不相等!
++ tot; //不相等个数加一
if (tot > 2) //超过两个数不一样了,不合法
return 0;
if (! cha) //第一个不相等的数,不能根据之前的数判断是否合法
cha = (a[i][j] - b[j] + 10) % 10; //计算需要转动的幅度
else if ((a[i][j] - b[j] + 10) % 10 != cha || last != j - 1) //和上次需要转动的幅度不等,或与上次不相等的位置不相邻,则不合法
return 0;
last = j; //别忘了记录!
}
}
return 1; //剩下就都合法了
}
void dfs (int step) { //普通 dfs,没必要讲吧
if (step > 4) { //递归结束条件
if (check ()) //判断是否合法
++ sum;
return ;
}
for (int i = 0; i < 10; ++ i)
b[step] = i, dfs (step + 1);
return ;
}
int main () {
ios::sync_with_stdio (0);
cin.tie (0);
cout.tie (0);
cin >> n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < 5; ++ j)
cin >> a[i][j];
dfs (0);
cout << sum;
return 0;
}

浙公网安备 33010602011771号