刷题日记 2024_2_2
原题链接:
题目分析
简单来说,这道题是也是bfs的搜索题。跟模板题不太一样的地方是,这道题不是搜索二维矩阵上某两点或多点之间的距离,而是某种状态到另一种状态之间的“距离”,且要打印输出具体过程。所以需要利用不同的数据结构来存储中间不同的状态。
unordered_map<string, int> dist;
unordered_map
是一种不排序的哈希表,unordered_map<string, int>
是字符串到整型的映射dist
用作记录两组字符串状态之间的距离
unordered_map<string, pair<char, string>> pre;
unordered_map<string, pair<char, string>>
是一种字符串到pair的映射pre.first
用于记录每次操作的名称 (A B C)pre.second
用于记录每次操作的状态(字符串)
为了方便我们可以把2*4的魔板用一位字符串来表示。那么魔板的三种操作也要转换成对应字符串上的操作:
A:交换上下两行 --> 正序变为倒序
string move0(string s)
{
for (int i = 0; i < 4; i++)
{
swap(s[i], s[7 - i]);
}
return s;
}
B:将最右边的一列插入到最左边
string move1(string s)
{
for (int i = 3; i > 0; i--)
{
swap(s[i], s[i - 1]);
}
for (int i = 4; i < 7; i++)
{
swap(s[i], s[i + 1]);
}
return s;
}
C:魔板中央对的4个数作顺时针旋转
string move2(string s)
{
swap(s[1], s[2]);
swap(s[1], s[6]);
swap(s[5], s[6]);
return s;
}
下面是bfs的代码部分:
void bfs()
{
q.push(start);
while (!q.empty())
{
string t = q.front();
q.pop();
string m[3];
m[0] = move0(t);
m[1] = move1(t);
m[2] = move2(t);
for (int i = 0; i < 3; i++)
{
if (!dist.count(m[i])) //如果这个状态没有出现过
{
q.push(m[i]);
dist[m[i]] = dist[t] + 1; //该状态是上一个状态“移动”1个步数得到的
pre[m[i]] = { 'A' + i,t }; //用于存储操作名称、状态名称
}
}
}
}
到这里基本的代码都已经解决了,还有最后一个问题:怎么打印输出操作序列?
这就要用到我们的pre
。具体操作如下:
int k = dist[endstring];
if (k)
{
while (k--)
{
res += pre[endstring].first;
endstring = pre[endstring].second;
}
reverse(res.begin(), res.end());
cout << res << endl;
}
整体代码展示:
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
const int N = 1e5 + 5;
string start = "12345678";
string endstring = "";
string res = "";
queue<string> q;
unordered_map<string, int> dist;
unordered_map<string, pair<char, string>> pre;
string move0(string s)
{
for (int i = 0; i < 4; i++)
{
swap(s[i], s[7 - i]);
}
return s;
}
string move1(string s)
{
for (int i = 3; i > 0; i--)
{
swap(s[i], s[i - 1]);
}
for (int i = 4; i < 7; i++)
{
swap(s[i], s[i + 1]);
}
return s;
}
string move2(string s)
{
swap(s[1], s[2]);
swap(s[1], s[6]);
swap(s[5], s[6]);
return s;
}
void bfs()
{
q.push(start);
while (!q.empty())
{
string t = q.front();
q.pop();
string m[3];
m[0] = move0(t);
m[1] = move1(t);
m[2] = move2(t);
//cout << "m[0]-->" << m[0] << endl;
//cout << "m[1]-->" << m[1] << endl;
//cout << "m[2]-->" << m[2] << endl;
//break;
for (int i = 0; i < 3; i++)
{
if (!dist.count(m[i]))
{
q.push(m[i]);
dist[m[i]] = dist[t] + 1;
pre[m[i]] = { 'A' + i,t };
}
}
}
}
int main()
{
char x = 0;
for (int i = 1; i <= 8; i++)
{
cin >> x;
endstring += x;
}
//cout << endstring << endl;
bfs();
cout << dist[endstring] << endl;
int k = dist[endstring];
if (k)
{
while (k--)
{
res += pre[endstring].first;
endstring = pre[endstring].second;
}
reverse(res.begin(), res.end());
cout << res << endl;
}
return 0;
}
一些反思:
这道题虽然思路不难,但是代码实现还是有点复杂,尤其是没有想到这种巧妙的数据结构之前。