【最小步数模型】魔板
原题链接
1. 题意解析
如果魔板的 原序列为
12345678
那么对应到魔板上就是
1 2 3 4
8 7 6 5
然后给出3种变化 ABC
求 所给一个序列 怎么可以变到 基准序列
问题一:ABC操作 具体怎么实现?
首先如果由于所给序列是
12345678
我们想到用string存储
那么存储是
12345678
还是
12348765?
尊重题意更好理解
我们可以存储
12348765
这样更好遵从题意,避免后序操作变复杂而变乱
那么接下来如何对ABC实现呢?
string change(string t,int i)
{
string tt;
if(i == 0)
{
tt = {t[4], t[5], t[6], t[7], t[0], t[1], t[2], t[3]};
}
if(i == 1)
{
tt = {t[3], t[0], t[1], t[2], t[7], t[4], t[5], t[6]};
}
if(i == 2)
{
tt = {t[0], t[5], t[1], t[3], t[4], t[6], t[2], t[7]};
}
return tt;
}
2. 普通算法
接下来,我们如何求呢
对于样例来说
所给是
2 6 8 4 5 7 3 1
那么魔板如下
2 6 8 4
1 3 7 5
那么把上述魔板 变成
1 2 3 4
8 7 6 5
我的第一想法是全排列
也就是按步骤排列
第一次变化可能是
ABC三种
第二次也是
ABC三种
以此类推
直到变到 基准序列
void bfs(int u)//u表示第几次遍历
{
for(int i = 0; i < 3; i++)//每个递归都进行三次操作
{
//如果A没有用过
//把A标记用过了
dfs(i+1)
//回溯后标记没用过
}
}
类似于上述的代码
但是这个有个问题就是
不知道何时剪纸或者 停止遍历
3. 优化算法
dfs不行
那么我们就得用bfs了
由于题目求得是
从 基准距离求到 所给得特殊距离
那么我们就把基准距离入队列
即可
那么如何记录 每个路径得长度??
string是固定得,
我们用
map<string,int>记录长度
如何记录路径变化?
我们用
map<string,pair<string,int>>记录当前stirng得上一个string并且上一个得路径 也记录下来了这样更方便
#include<iostream>
#include<unordered_map>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
char a[10];
string start;
string change(string t,int i)
{
string tt;
if(i == 0)
{
tt = {t[4], t[5], t[6], t[7], t[0], t[1], t[2], t[3]};
}
if(i == 1)
{
tt = {t[3], t[0], t[1], t[2], t[7], t[4], t[5], t[6]};
}
if(i == 2)
{
tt = {t[0], t[5], t[1], t[3], t[4], t[6], t[2], t[7]};
}
return tt;
}
void bfs()
{
queue<string> q;
unordered_map<string,int> st;
unordered_map<string,pair<string,int>> pre;
q.push("12348765");
st["12348765"] = 0;
while(q.size())
{
auto t = q.front(); q.pop();
for(int i = 0; i < 3; i++)
{
string tt = change(t,i);
if(st.count(tt)==0)
{
q.push(tt);
st[tt] = st[t]+1;
pre[tt] = {t,i};
}
if(tt==start)
{
cout << st[tt] << endl;
string s = start;
// cout << pre[tt].first << endl;
// cout << tt << endl;
string end;
while("12348765"!=s)
{
char op = pre[s].second+'A';
end+=op;
//cout << op;
s = pre[s].first;
}
reverse(end.begin(),end.end());
cout << end;
return;
}
}
}
}
int main()
{
for(int i = 1; i <= 8; i++) cin >> a[i];
reverse(a+5,a+9);
for(int i = 1; i <= 8; i++) start+=a[i];
bfs();
return 0;
}