P2730 [USACO3.2]魔板 Magic Squares

[USACO3.2]魔板 Magic Squares

题目背景

在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有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

样例输入 #1

2 6 8 4 5 7 3 1

样例输出 #1

7 
BCABCCB

提示

题目翻译来自NOCOW。

USACO Training Section 3.2

首先,请忘记康托展开,STL大法好!

大致思路:

  • 这是一道很明显的bfs题,可以反过来广搜判断,基本状态什么时候可以到输入的目标状态。
  • 去掉重复的,因为重复的我们之前就在更早的时候到达过了,一定不会优于之前,且会导致无限循环。
  • 书上采取的办法是Hash,康托展开,实际上map更好用一点。

map用法

成员方法功能
map< int > m定义一个map
begin()返回指向容器中第一个(已排好序的第一个)键值对的双向迭代器
end()返回指向容器中最后一个元素(已排好序的最后一个)所在位置的后一个位置的双向迭代器。
rbegin()返回指向容器中最后一个(已排好序的最后一个)元素的反向双向迭代器。
rend()返回指向容器中第一个(已排好序的第一个)元素所在位置的前一个位置的反向双向迭代器。
cbegin()和begin()功能相同,只不过在其基础上,增加了const属性,不能用于修改容器内储存的键值对。
cend()和end()功能相同,只不过在其基础上,增加了const属性,不能用于修改容器内储存的键值对。
crbegin()和rbegin()功能相同,只不过在其基础上,增加了const属性,不能用于修改容器内储存的键值对。
crend()和rend()功能相同,只不过在其基础上,增加了const属性,不能用于修改容器内储存的键值对。
find(key)在map容器中查找键为key的键值对,若成功找到,则返回指向该键值对的双向迭代器;若未找到,则返回和end()方法一样的迭代器。
lower_bound(key)返回一个指向当前map容器中第一个大于或等于key的键值对的双向迭代器。
upper_bound(key)返回一个指向当前map容器中第一个大于key的键值对的双向迭代器。
equal_range(key)返回一个pair对象(包含2个双向迭代器),其中pair.first和lower_bound()方法的返回值等价,pair.second和upper_bound()方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为key的键值对(map容器键值对唯一,因此该返回最多包含一个键值对)。
count()查找本元素是否存在
————————————————
详细见STL map详细用法
  • 用map存储每个字符串,将其作为下标,其中的值存储经过了哪些操作
  • 对于操作ABC,我们可以定义函数来实现他们,对应样例,不过多解释。
string A(string xx){
	string x,y;
	for(int i=0;i<4;i++){
		x+=xx[3-i];
		y+=xx[7-i];
	}
	xx=y+x;
	return xx;
}
string B(string xx){
	string x=xx;
	xx[0]=x[3];xx[1]=x[0];xx[2]=x[1];xx[3]=x[2];
	xx[4]=x[5];xx[5]=x[6];xx[6]=x[7];xx[7]=x[4];
	return xx;
}
string C(string xx){
	string x=xx;
	xx[1]=x[6];xx[2]=x[1];xx[5]=x[2];xx[6]=x[5];
	return xx;
}
  • 剩下的就是bfs模板啦,通过队列实现一层层的搜索

AC CODE

#include<queue>
#include<bits/stdc++.h>
using namespace std;
string a,aa;
int ans=0;
map<string,string>m;
queue <string> q;
string A(string xx){
	string x,y;
	for(int i=0;i<4;i++){
		x+=xx[3-i];
		y+=xx[7-i];
	}
	xx=y+x;
	return xx;
}
string B(string xx){
	string x=xx;
	xx[0]=x[3];xx[1]=x[0];xx[2]=x[1];xx[3]=x[2];
	xx[4]=x[5];xx[5]=x[6];xx[6]=x[7];xx[7]=x[4];
	return xx;
}
string C(string xx){
	string x=xx;
	xx[1]=x[6];xx[2]=x[1];xx[5]=x[2];xx[6]=x[5];
	return xx;
}
int main(){
	for(int i=0;i<8;i++){
		char a1;
		cin>>a1;
		a+=a1;//字符串拼接
		getchar();//读入空格
	}
	q.push("12345678");
	m["12345678"]="";
	while(!q.empty()){
		aa=q.front();
		string h;
		h=A(aa);
		if(m.count(h)==0){//如果操作A的结果没有出现过
			q.push(h);//入队
			m[h]=m[aa]+'A';//进行了操作A,记录
		}
		h=B(aa);
		if(m.count(h)==0){//如果操作B的结果没有出现过
			q.push(h);//入队
			m[h]=m[aa]+'B';//进行了操作B,记录
		}
		h=C(aa);
		if(m.count(h)==0){//如果操作C的结果没有出现过
			q.push(h);//入队
			m[h]=m[aa]+'C';//进行了操作C,记录
		}
		if(m.count(a)!=0){//找到答案
			cout<<m[a].size()<<endl;//进行了多少操作
			cout<<m[a];//进行了哪些操作
			break;
		}
		q.pop();
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值