题目描述
某行李箱支持4位数字密码,每位数字在0和9之间,开锁方式:
每次操作改变其中1位数字。(注意,是改变,比如0023改变第4位后,变成0029)每次操作后的数字必须始终是素数(如23和29是素数)。
现给定行李箱的初始密码与解锁密码(都是素数,包含前导0),请找出最快的开锁方式(改变次数最少),输出改变次数,如果无法解锁,输出-1。
解答要求
时间限制:1000ms,内存限制:256MB
输入
两个4位数字字符,分别表示初始密码与解锁密码,以单个空格分隔。
输出
一个整数,表示开锁的最少改变次数;无法解锁则输出-1。
样例
输入样例1
0023 0059
输出样例1
2
提示样例1
0023->0059,存在两种开锁方式:0023->0029->0059,或0023->0053->0059,操作次数都是2
输入样例2
1373 8017,存在一种开锁方式:1373->0373->0313->0317->8317->8017,需要5次操作。
提示
素数,又称质数,指在大于1的自然数中,除了1和该数自身外,无法被其它自然数整除的数。
解题思路:
1、行李箱只有4位数,搜索过程中需要判断是否为素数。可以利用埃氏筛将10000以内的素数都做好标记。
2、定义一个queue存放将要搜索的数,unordered_set存放已经遍历过的数(避免重复遍历)
3、分别对四位数的每一位进行BFS遍历,0023 (0023,1023, 2023, 3023 ****,这里只需要保留素数)
4、对初始值的每一位遍历一次,则step+1.
5、对上一步遍历得到的中间数(满足要求的素数)进行第二次遍历(同样四位数每一位遍历,只保留素数),如果得到最终的密码,则退出。
代码如下:
C++
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set>
using namespace std;
const int MAXLEN = 10000;
vector<bool> ISPRIME(MAXLEN, true);
//埃氏筛
void isPrimeInit()
{
ISPRIME[0] = false;
ISPRIME[1] = false;
for(int i = 2; i < MAXLEN; i++) {
if(ISPRIME[i]) {
for(int j = 2; j <= MAXLEN; j++) {
if(i*j >= MAXLEN) {
break;
}
ISPRIME[i*j] = false;
}
}
}
}
int getStepUnlock(const string &initState, const string &dstState)
{
int step = 0;
queue<string> st;
unordered_set<string> visit;
st.push(initState);
visit.insert(initState);
isPrimeInit();
while(!st.empty()) {
int len = st.size();
#if 0
cout << "len:" << len << endl;
queue<string> temp = st;
while(!temp.empty()) {
cout << temp.front() << " ";
temp.pop();
}
cout << endl;
#endif
for(int i = 0; i < len; i++) {
string cur = st.front();
st.pop();
if(cur == dstState) {
return step;
}
for(int j = 0; j < 4; j++) {
string tmp = cur;
for(int k = 0; k <= 9; k++) {
tmp[j] = k + '0';
if(ISPRIME[stoi(tmp)] && visit.insert(tmp).second) {
st.push(tmp);
}
}
}
}
step++;
}
return step;
}
int main()
{
string initPasswd;
string unlockPasswd;
cin >> initPasswd >> unlockPasswd;
cout << getStepUnlock(initPasswd, unlockPasswd) << endl;
}
输出如下:
python写法:
#!/usr/bin/env python
# coding=utf-8
class Solution:
ISPRIME = [True] * 10000
def isPrimeInit(self):
self.ISPRIME[0] = False;
self.ISPRIME[1] = False;
for i in range(2,10000):
if self.ISPRIME[i]:
for j in range(2,10000):
if i*j >= 10000:
break;
self.ISPRIME[i*j] = False
def getStepUnlock(self, initState, dstState):
st = []
visit = set()
step = 0
st.append(str(initState))
visit.add(str(initState))
length = 0
self.isPrimeInit()
while st:
length = len(st)
for i in range(length):
cur = st.pop(0)
if cur == dstState:
return step
for j in range(4):
tmp = cur
for k in range(10):
tmp = tmp[:j] + str(k) + tmp[j+1:]
if self.ISPRIME[int(tmp)] and tmp not in visit:
st.append(tmp)
step += 1
return step
if __name__ == "__main__":
initPasswd, unlockPasswd = input().strip().split();
function = Solution();
print(function.getStepUnlock(initPasswd, unlockPasswd))