Luggage Lock( The 2021 ICPC Asia Shenyang Regional Contest )

Luggage Lock( The 2021 ICPC Asia Shenyang Regional Contest

题面描述:

Eileen has a big luggage and she would pick a lot of things in the luggage every time when A-SOUL goes out for a show. However, if there are too many things in the luggage, the 4-digit password lock on the luggage will be hard to rotate.

The state of lock is the four digits on the lock. In one step, she can choose consecutive digits to rotate up by one simultaneously or down by one simultaneously . For example, she can rotate 0000 \texttt{0000} 0000 to 0111 \texttt{0111} 0111 or 0900 \texttt{0900} 0900 in one step because the rotated digits are consecutive, but she can't rotate 0000 \texttt{0000} 0000 to 0101 \texttt{0101} 0101 in one step. Since she has little strength, she wants to rotate the lock as few times as possible.

Now the lock is at state a 0 a 1 a 2 a 3 a_0a_1a_2a_3 a0a1a2a3 and the password is b 0 b 1 b 2 b 3 b_0b_1b_2b_3 b0b1b2b3. As a fan of A-SOUL, you are asked to help Eileen find out the optimal plan to unlock but you only need to tell Eileen how many times she has to rotate.

input

The first line contains one integer T T T ( 1 ≤ T ≤ 1 0 5 ) (1 \leq T \leq 10^5) (1≤T≤105), denoting the numer of test cases.

Each of the test cases contains a line containing the initial state a 0 a 1 a 2 a 3 a_0a_1a_2a_3 a0a1a2a3 and the target state b 0 b 1 b 2 b 3 b_0b_1b_2b_3 b0b1b2b3.

output

For each test case, output a line containing a single integer, denoting the minimum steps needed to unlock.

Exemple
复制代码
6
1234 2345
1234 0123
1234 2267
1234 3401
1234 1344
1234 2468

1
1
4
5
1
4

题目大意

Eileen有一个大行李箱,每次出门时她需要从行李箱中拿很多东西。然而,如果行李箱内放置的物品太多,四位数密码锁的旋转就会变得困难。

密码锁的状态是四个数字。在每一步中,Eileen可以选择连续的数字,将它们同时向上或向下旋转1。比如,她可以将0000旋转到01110900,但不能将0000旋转到0101,因为它们不是连续的数字。由于她力量有限,她希望以最少的步骤旋转密码锁。

现在,密码锁的状态是a0a1a2a3,目标密码是b0b1b2b3。作为A-SOUL的粉丝,你被要求帮助Eileen找出解锁的最优方案,但你只需要告诉Eileen需要多少步旋转才能解锁。


思路

这是一道很明显的bfs+模拟的题(和八数码是一类题)

其实可以采用离线,并且理解题目为从"0000"到目标状态的旋转次数!!!

比如说:"1234"到"2345"就相当于从"0000"到"1111"或者说"9999"

因为密码旋转本身就是环形结构,所以说可以一样操作。

因 为 起 点 和 终 点 都 不 一 样 , 还 有 1 e 5 个 测 试 样 例 。 因 此 不 能 直 接 对 每 一 组 样 例 都 做 一 遍 b f s , 肯 定 会 超 时 。 因为起点和终点都不一样,还有1e5个测试样例。因此不能直接对每一组样例都做一遍bfs,肯定会超时。因为起点和终点都不一样,还有1e5个测试样例。因此不能直接对每一组样例都做一遍bfs,肯定会超时。

因 此 我 们 可 以 将 所 有 测 试 样 例 的 起 点 都 转 化 为 0000 , 终 点 对 应 变 为 t [ i ] − s [ i ] ( s 为 起 点 , t 为 终 点 ) 因此我们可以将所有测试样例的起点都转化为0000,终点对应变为t[i]-s[i](s为起点,t为终点)因此我们可以将所有测试样例的起点都转化为0000,终点对应变为t[i]−s[i](s为起点,t为终点)

这 样 转 换 之 后 , 我 们 可 以 以 0000 作 为 起 点 进 行 一 遍 b f s , 同 时 记 录 下 到 达 每 个 状 态 所 需 的 步 数 。 这 样 对 于 这样转换之后,我们可以以0000作为起点进行一遍bfs,同时记录下到达每个状态所需的步数。这样对于这样转换之后,我们可以以0000作为起点进行一遍bfs,同时记录下到达每个状态所需的步数。这样对于每 个 测 试 样 例 即 可 O ( 1 ) 输 出 答 案 。 每个测试样例即可O(1)输出答案。每个测试样例即可O(1)输出答案。

代码实现

cpp 复制代码
#include <map>
#include <set>
#include <fstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdio>
#include <bitset>
#include <iomanip>
#define endl '\n'
#define int long long
#define Max(a, b) (((a) > (b)) ? (a) : (b))
#define Min(a, b) (((a) < (b)) ? (a) : (b))
#define BoBoowen ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;

const int inf = 1e9 + 7;
const int N = 2e5 + 10;
map<string, int> mp;

void bfs(string s)
{
    string fir = "0000";
    queue<string> q;
    q.push(fir);
    mp[fir] = 0;

    while (!q.empty())
    {
        string now = q.front();
        q.pop();
        for (int i = 0; i < 4; ++i)
        {
            int cz = 1;
            for (int k = 0; k < 2; ++k)
            {
                cz *= -1;
                string nex = now;
                for (int j = 0; j + i < 4; ++j)
                {
                    nex[i + j] = (nex[i + j] - '0' + cz + 10) % 10 + '0';
                    if (mp[nex] == 0 && nex != fir)
                    {
                        // cout << nex << endl;
                        mp[nex] = mp[now] + 1;
                        q.push(nex);
                    }
                }
            }
        }
    }
}

void solved()
{
    string s1, s2;
    cin >> s1 >> s2;
    string s;
    for (int i = 0; i < 4; ++i)
    {
        s += (s1[i] - s2[i] + 10) % 10 + '0';
    }
    // cout << s << endl;
    cout << mp[s] << endl;
}

signed main()
{
    BoBoowen;
    bfs("0000");
    int T = 1;
    cin >> T;
    while (T--)
    {
        solved();
    }
}

小小解读

  • mp 是一个 map,用来存储每个状态到达该状态的最小步数。
  • bfs 函数负责从初始状态 0000 开始进行广度优先搜索,计算到达每个状态的最小步数。
  • q 是一个队列,用来存储待探索的状态。
  • mp 存储每个状态的最小步数。初始时,将状态 0000 的步数设为 0。
  • 对于每个状态,尝试选择一个连续的子序列进行旋转操作。这里旋转有两种方式:顺时针(cz = 1)和逆时针(cz = -1)。
  • 每次旋转操作后,如果新的状态未被访问过,就将该状态加入队列并更新步数。
  • solved 函数负责处理每个测试用例。
  • 从输入中读取当前状态 s1 和目标状态 s2
  • 计算 s1s2 之间的差值,并转换成一个新的状态 s。这个差值表示需要旋转的步骤,(s1[i] - s2[i] + 10) % 10 保证了旋转结果始终在 0 到 9 之间。
  • 最后,输出该状态到达目标所需的最小步数,即 mp[s]
  • 主函数中,先调用 bfs("0000") 函数初始化所有从 0000 到其他状态的最小步数。
  • 然后通过循环处理每个测试用例。

总结

  • BFS 算法 :用广度优先搜索遍历所有状态,确保找到从 0000 到目标状态的最小步数。
  • 状态转换:每次旋转一个连续的子序列,旋转方式有顺时针和逆时针。
  • 时间复杂度 :由于 bfs 函数会遍历所有可能的状态,因此时间复杂度为 O(10^4),由于最多有 T 个测试用例,总的时间复杂度大约是 O(T * 10^4),对于 T = 10^5,每个测试用例的计算时间是常数时间,能够满足题目的要求。
相关推荐
明明真系叻7 分钟前
2025.4.20机器学习笔记:文献阅读
人工智能·笔记·机器学习
kfepiza1 小时前
HttpSessionListener 的用法笔记250417
java·笔记·servlet·tomcat
铭阳(●´∇`●)2 小时前
Python内置函数---anext()
笔记·python·学习
路上^_^2 小时前
CSS核心笔记001
前端·css·笔记
十年之少2 小时前
网络请求——微信小程序学习笔记
笔记·学习·微信小程序
郭涤生4 小时前
QML 信号与槽
c++·笔记·qt
cwtlw4 小时前
PhotoShop学习10
笔记·学习·其他·photoshop
梦の4 小时前
C++Cherno 学习笔记day20 [81]-[85] 可视化基准测试、单例模式、小字符串优化sso、跟踪内存分配、左值与右值
c++·笔记·学习
BIOS菜鸟工程师5 小时前
UEFI Spec 学习笔记---12 - Protocols —CONSOLE SUPPORT(一)
人工智能·笔记·学习
MrsBaek5 小时前
前端笔记-JavaScript部分(中)
前端·javascript·笔记