https://www.luogu.com.cn/problem/P2730
题目背景
在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有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”:魔板中央四格作顺时针旋转。
下面是对基本状态进行操作的示范:
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个整数,用空格分开(这些整数在范围 1——8 之间)不换行,表示目标状态。
输出格式
Line 1: 包括一个整数,表示最短操作序列的长度。
Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。
输入输出样例
输入 #1复制
2 6 8 4 5 7 3 1
输出 #1复制
7 BCABCCB
说明/提示
题目翻译来自NOCOW。
USACO Training Section 3.2
这道题对于我来说,逻辑和编码方面都有很大的挑战,在思考未过之后,翻了一些大佬的题解,发现他们使用map容器来写。在写这道题的过程中,我遇到的最大的挑战就是,1.将输入的整型数据转换成string,2.关于map容器的用法并不熟悉。
收获:
1.关于整形数字转换成字符串:
string e; int t;
e+=t+'0';
/*在这个地方e是string类型,而t是int类型 ,t+'0'是char类型,
但是最好还是用e+=t+'0'或e+=char(t+'0')来表示,e[i]=t+'0'来表示的话,
虽然可以表示出来e[i]但是string e 可能会出错
*/2.关于map相关的一些用法:
#include<map>
map<key, value> m;//创建一个名为m的空map对象,其键和值的类型分别为key和value。
map<key, value> m(m2);//创建m2的副本m,m与m2必须有相同的键类型和值类型。
map<key, value> m(b,e);//创建map类型的对象m,存储迭代器b和e标记的范围内所有元素的副本,元素的类型必须能转换为pair
//查
m.count(k);// 返回m中键值等于k的元素的个数。
m.find(k);// 如果m中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回结束游标end()。
//删
//迭代器刪除
iter = m.find("123");
m.erase(iter);
//用关键字刪除
int n = m.erase("123"); //如果刪除了會返回1,否則返回0
//用迭代器范围刪除 : 把整个map清空
m.erase(m.begin(), m.end());
//等同于m.clear()
m.erase(k); // 删除m中键为k的元素,返回size_type类型的值,表示删除元素的个数。
m.erase(p); // 从m中删除迭代器p所指向的元素,p必须指向m中确实存在的元素,而且不能等于m.end(),返回void类型。
m.erase(iterator first, iterator last); // 删除一个范围,返回void类型。
//插入
// 第一种 用insert函數插入pair
m.insert(pair<int, string>(000, "student_zero"));
// 第二种 用insert函数插入value_type数据
m.insert(map<int, string>::value_type(001, "student_one"));
// 第三种 用"array"方式插入
m[123] = "student_first";
m[456] = "student_second";
m.insert(e) ;
e是一个用在m上的value_type类型的值。如果键e.first不在m中,则插入一个值为e.second的新元素;如果该键在m中已存在,那么不进行任何操作。该函数返回一个pair类型对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素。
m.insert(beg, end);
beg和end是标记元素范围的迭代器,对于该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m。 返回void类型。
m.insert(iter, e);
e是value_type类型的值,如果e.first不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置,返回一个迭代器,指向m中具有给定键的元素。 在添加新的map元素时,使用insert成员可避免使用下标操作符带来的副作用:不必要的初始化。
//在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:
int nSize = mapStudent.size();
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
#include<string>
using namespace std;
map<string,string> my;
queue<string> qu;
string e;
void A(string s){
string s1=s;
for(int i=0;i<8;i++){
s1[i]=s[7-i];
}
if(my.count(s1)==0){ //s1未出现过
qu.push(s1);
my[s1]=my[s]+'A';//重点 <<<<<<,写的格式要记住
}
return ;
}
void B(string s){
string s1=s;
s1[0]=s[3];
for(int i=1;i<4;i++){
s1[i]=s[i-1];
}
for(int i=4;i<7;i++){
s1[i]=s[i+1];
}
s1[7]=s[4];
if(my.count(s1)==0){
qu.push(s1);
my[s1]=my[s]+'B';
}
return ;
}
void C(string s){
string s1=s;
s1[1]=s[6];
s1[2]=s[1];
s1[5]=s[2];
s1[6]=s[5];
if(my.count(s1)==0){
qu.push(s1);
my[s1]=my[s]+'C';
}
return ;
}
void bfs(){
while(!qu.empty()){
string now=qu.front();
qu.pop();
A(now);
B(now);
C(now);
if(my.count(e)!=0){ //当转变成目标序列后,输出
cout<<my[e].size()<<endl;
cout<<my[e]<<endl; //还未遇见过的写法
return ;
}
}
}
int main(){
qu.push("12345678");
my["12345678"]="";
for(int i=0;i<8;i++){
int t;
cin>>t;
e+=t+'0';
/*在这个地方e是string类型,而t是int类型 ,t+'0'是char类型,
但是最好还是用e+=t+'0'或e+=char(t+'0')来表示,e[i]=t+'0'来表示的话,
虽然可以表示出来e[i]但是string e 可能会出错
*/
}
bfs();
return 0;
}