OJ【素数行李箱密码】

题目描述
某行李箱支持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))

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值