Gym - 103427J Luggage Lock
Gym - 103427J Luggage Lock
题解:BFS预处理+偏移
首先我们考虑暴力做法,对于每次查询我们都去找出\(a_0a_1a_2a_3\)到\(b_0b_1b_2b_3\)的最小步骤,如果给你0000->9999,我们需要遍历1e4中状态,所以1e5次查询,显然数量级为1e9>1e8
所以我们肯定要考虑预处理,那怎么预处理呢?
我们来看一个例子:
2356-->4273 我们对他做偏移处理得到:0000-->2927,那么是不是就意味着两者从前一种状态到后一种状态的最小步骤是一样的,所以我们可以先预处理出0000到所有情况的最短步骤,然后对于每次的询问,我们进行偏移处理,变成0000-->\(c_0c_1c_2c_3\)的情况,这样能够实现\(O(1)\)询问
我们再来看怎么去BFS,首先他只能对一个连续的区间进行上拨和下拨,所以我们只要对[0,0] , [0,1], [0,2]....[3,3]
共10个区间进行上拨和下拨的操作,这样实际上每个点有20条边,所以实际上\(a_0a_1a_2a_3\)可以转化为另外20个数字,同时我们利用map进行记忆化和存储预处理结果
#include <iostream>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <string>
#include <string.h>
#include <ctype.h>
#include <vector>
#include <math.h>
#include <queue>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 4e4 + 10;
int n, m;
map<string, ll> mp; //存储预处理结果和进行记忆化搜索
struct node
{
string str;
ll step;
};
void bfs()
{
queue<node> q;
node t;
t.str = "0000"; //从初始0000开始,但是可以是任意状态开始
t.step = 1; //设为1,防止直接退出循环
q.push(t);
while (q.size())
{
t = q.front();
q.pop();
if (mp[t.str]) //记忆化
continue;
mp[t.str] = t.step;
for (int i = 0; i < 4; ++i) // 往上转共10种情况
{
for (int j = i; j < 4; ++j)
{
string s = t.str;
for (int k = i; k <= j; ++k)
{
s[k] = (s[k] - '0' + 1) % 10 + '0';
}
node tmp;
tmp.str = s;
tmp.step = t.step + 1;
q.push(tmp);
}
}
for (int i = 0; i < 4; ++i) // 往下转共10种情况
{
for (int j = i; j < 4; ++j)
{
string s = t.str;
for (int k = i; k <= j; ++k)
{
s[k] = (s[k] - '0' + 10 - 1) % 10 + '0';
}
node tmp;
tmp.str = s;
tmp.step = t.step + 1;
q.push(tmp);
}
}
}
}
int main(void)
{
Zeoy;
int t = 1;
bfs();
cin >> t;
while (t--)
{
string s1, s2;
cin >> s1 >> s2;
string ans = "0000";
for (int i = 0; i < 4; ++i)
{
ans[i] = (s2[i] - s1[i] + 10) % 10 + '0';
}
cout << mp[ans] - 1 << endl;
}
return 0;
}