最小步数模型(魔板,bfs,map)

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值