Rubik 先生在发明了风靡全球的魔方之后,又发明了它的二维版本——魔板。
这是一张有 8 个大小相同的格子的魔板:
1 2 3 4
8 7 6 5
我们知道魔板的每一个方格都有一种颜色。
这 8 种颜色用前 8 个正整数来表示。
可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。
对于上图的魔板状态,我们用序列 (1,2,3,4,5,6,7,8) 来表示,这是基本状态。
这里提供三种基本操作,分别用大写字母 A,B,C 来表示(可以通过这些操作改变魔板的状态):
A:交换上下两行;
B:将最右边的一列插入到最左边;
C:魔板中央对的4个数作顺时针旋转。
下面是对基本状态进行操作的示范:
A:
8 7 6 5
1 2 3 4
B:
4 1 2 3
5 8 7 6
C:
1 7 2 4
8 6 3 5
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到特殊状态的转换,输出基本操作序列。
注意:数据保证一定有解。
输入格式
输入仅一行,包括 8 个整数,用空格分开,表示目标状态。
输出格式
输出文件的第一行包括一个整数,表示最短操作序列的长度。
如果操作序列的长度大于0,则在第二行输出字典序最小的操作序列。
数据范围
输入数据中的所有数字均为 1 到 8 之间的整数。
输入样例:
2 6 8 4 5 7 3 1
输出样例:
7
BCABCCB
解析:
这种题目很简单,但是对码代码能力很考验。
因为有三种变换,且必须字典序最小输出。所以我们要按照A,B,C这三个操作顺序放到队列里面去。如果队列已经存在了,那就不放。还需要记录一下前驱
#include<bits/stdc++.h> using namespace std; char g[2][4]; unordered_map<string, pair<char, string>> pre;//记录前驱+答案 unordered_map<string, int> dist; //记录距离 int x; void set1(string t) {
for(int i=0;i<4;i++) g[0][i]=t[i]; for(int i=7,j=0;j<4;j++,i--) g[1][j]=t[i]; } string get() {
string res; for(int i=0;i<4;i++) res+=g[0][i]; for(int i=3;i>=0;i--) res+=g[1][i]; return res; } string move0(string t) {
set1(t); for(int i=0;i<4;i++) swap(g[0][i],g[1][i]); return get(); } string move1(string t) {
set1(t); int v0 = g[0][3], v1 = g[1][3]; for (int i = 3; i >= 0; i -- ) {
g[0][i] = g[0][i - 1]; g[1][i] = g[1][i - 1]; } g[0][0] = v0, g[1][0] = v1; return get(); } string move2(string t) {
set1(t); int v = g[0][1]; g[0][1] = g[1][1]; g[1][1] = g[1][2]; g[1][2] = g[0][2]; g[0][2] = v; return get(); } int bfs(string start,string end) {
if(start==end) return 0; //如果一开始就相等,返回0 queue<string > q; q.push(start);//一开始的状态放入到队列 dist[start]=0;//初始化距离 while(q.size()) {
auto 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]))//没出现过 {
dist[m[i]]=dist[t]+1;//步数+1 pre[m[i]]={
'A'+i,t}; q.push(m[i]);//入队 if(m[i]==end) return dist[end];//正好等于最终状态返回。 } } } return -1; } int main() {
string start,end; for(int i=0;i<8;i++) {
cin>>x; end+=char(x+'0'); } for(int i=0;i<8;i++) start+=char(i+'1'); int k=bfs(start,end); cout<<k<<endl; string res; while(end!=start) {
res+=pre[end].first; end=pre[end].second; } reverse(res.begin(),res.end()); if(k>0) cout<<res<<endl; }
今天的文章
魔板-------------------------------最小步数模型分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/82881.html