- 题目
题目描述
Bob最新购入一款安卓手机,他发现安卓手机密码使用的是画线方式。
一共有9个点,我们按行列顺序依次为1~9。密码要求在点和点之间连线不能有还未曾经过的点。
比如说:从1出发,可以到2,4,5,6,7,8,但是不能到达3,7,9。
但是如果从2出发,先到1,这时因为2已经经过了,所以此时可以到达3。
现在给你一个密码,请问它是否符合密码的这个要求?
输入
第一行是一个整数T(1≤T≤10000),表示样例的个数。
一个样例占一行,是一个最短为4位,最长9位,只含1-9的字符串,且1-9最多只有1个。
输出
每个样例输出一行,如果合法输出“Yes”,否则输出“No”。
样例输入
3
16852
213
132
样例输出
Yes
Yes
No
- 解法
用一个10 * 10的数组(9 * 9也行),用10 * 10是为了方便存储各个安卓密码数字之间的关系。如果从一个数字能直接到达另外一个数字则对应的数组元素为0(如数字5可以直接到达数字1,则a[5][1] = 0);如果不可能到达则对应数组元素为-1;如果必须要通过其他数字到达,则对应数组元素为要通过的数字(如1必须要通过4才能到7)。然后按照逻辑判断即可(主要意会简单,言传很难,所以就不详细写了)。我的代码如下。
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
int a[10][10] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, -1, 0, 2, 0, 0, 0, 4, 0, 5},
{0, 0, -1, 0, 0, 0, 0, 0, 5, 0},
{0, 2, 0, -1, 0, 0, 0, 5, 0, 6},
{0, 0, 0, 0, -1, 0, 5, 0, 0, 0},
{0, 0, 0, 0, 0, -1, 0, 0, 0, 0},
{0, 0, 0, 0, 5, 0, -1, 0, 0, 0},
{0, 4, 0, 5, 0, 0, 0, -1, 0, 8},
{0, 0, 5, 0, 0, 0, 0, 0, -1, 0},
{0, 5, 0, 6, 0, 0, 0, 8, 0, -1}
};
void toNum(char *s) {
for(int i = 0; i < strlen(s); i++) {
s[i] -= 48;
}
}
bool f(char *s) {
bool flag = true;
toNum(s);
for(int i = 0; i < strlen(s) - 1; i++) {
if(a[s[i]][s[i+1]] == 0) {//如果可直接到达
continue;
} else if(a[s[i]][s[i+1]] > 0) { //否则 往前找有没有经过必须要经过的辅助
bool b = false;
for(int j = 0; j < i; j++) {
if(s[j] == a[s[i]][s[i+1]]) {
b = true;
break;
}
}
if(!b) {
flag = false;
}
} else {
flag = false;
}
}
return flag;
}
using namespace std;
int main(int argc, char const **argv) {
int K;
char s[9];
cin >> K;
while(K--) {
cin >> s;
if(f(s)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}