[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

读题

8数码

典型的8数码问题是一种经典的搜索问题。在《算法竞赛入门经典》,即紫书中,对此问题十分重视,建议读者可以优先做一下8数码问题。
在该问题中,我们需要将一个3x3的九宫格拼图恢复到目标状态,即初始状态为"12345678 “,目标状态为” 87654321"。每个格子上都有一个数字,但其中一个格子是空白格,可以与相邻的格子交换位置。我们的任务是找到一种从初始状态到目标状态的最短操作序列。

魔板

相信读者已经对8数码和紫书有了了解,我们继续看此题。

BFS:
在这道题中,我们可以将每个状态看成一个节点,并使用广度优先搜索算法来找到从初始状态到目标状态的一条最短路径。具体地,我们从初始状态开始,尝试对其施加A、B和C三种基本操作,并计算得到新状态。如果新状态没有被访问过,则将其加入队列。我们不断从队列中取出最早加入的状态进行处理,直到找到目标状态。
操作:
除了标准的BFS算法,我们还需要记录从初始状态到每个节点的操作序列。具体地,对于每个状态,在其相应的信息中记录从初始状态到该状态所使用的基本操作序列A、B和C。当我们找到目标状态时,输出该状态的操作序列即可。
难点:
如何表示状态和操作并有效地进行判重?在读过紫书后,我们知道有三种方法(编码与解码,哈希技术,set)在本题中,我们可以将状态看成一个字符串,并通过哈希表或集合记录已经访问过的节点。那么为了好理解,我们选用set与hash

大致思路 (废话):我们可以使用广度优先搜索算法来找到从初始状态到目标状态的最短路径,并输出操作序列。

代码

#include<bits/stdc++.h>
using namespace std;
struct mb{string xu;char xl[8];
};
mb first;
char en[10];
queue<mb> qu;
unordered_set<int> pc;
mb A(mb t){mb a;a.xu=t.xu+"A";for (int i=0;i<8;i++)a.xl[i]=t.xl[7-i];return a;
}
mb B(mb t){mb b;b.xu=t.xu+"B";b.xl[0]=t.xl[3],b.xl[1]=t.xl[0];b.xl[2]=t.xl[1],b.xl[3]=t.xl[2];b.xl[4]=t.xl[5],b.xl[5]=t.xl[6];b.xl[6]=t.xl[7],b.xl[7]=t.xl[4];return b;
}
mb C(mb t){mb c;c.xu=t.xu+"C";for (int i=0;i<8;i++)c.xl[i]=t.xl[i];c.xl[1]=t.xl[6],c.xl[2]=t.xl[1];c.xl[5]=t.xl[2],c.xl[6]=t.xl[5];return c;
}
bool vis(mb t){int l;sscanf(t.xl,"%d",&l);if (pc.count(l)==0) {pc.emplace(l);return true;}else return false;
}
bool check(mb t){for (char i=0;i<8;i++){if (t.xl[i]!=en[i]) return false;}return true;
}
void bfs(){while (!qu.empty()){mb tmp,now=qu.front();qu.pop();if (check(now)) {cout<<now.xu.size()<<endl<<now.xu;return;}tmp=A(now);if (vis(tmp)) qu.push(tmp);tmp=B(now);if (vis(tmp)) qu.push(tmp);tmp=C(now);if (vis(tmp)) qu.push(tmp);}return;
}
int main(){first.xu="";for (char i='1';i<'9';i++) first.xl[i-1-'0']=i;for (int i=0;i<8;i++){cin>>en[i];getchar();}qu.push(first);bfs();return 0;
}

分析

在mb(魔板)结构体中,string型的xu保存了操作顺序,并可以使用size()获取进行了多少次操作,而xl则保存了目前状态

操作

一共三种操作,用代码很好实现:

mb A(mb t){mb a;a.xu=t.xu+"A";for (int i=0;i<8;i++)a.xl[i]=t.xl[7-i];return a;
}
mb B(mb t){mb b;b.xu=t.xu+"B";b.xl[0]=t.xl[3],b.xl[1]=t.xl[0];b.xl[2]=t.xl[1],b.xl[3]=t.xl[2];b.xl[4]=t.xl[5],b.xl[5]=t.xl[6];b.xl[6]=t.xl[7],b.xl[7]=t.xl[4];return b;
}
mb C(mb t){mb c;c.xu=t.xu+"C";for (int i=0;i<8;i++)c.xl[i]=t.xl[i];c.xl[1]=t.xl[6],c.xl[2]=t.xl[1];c.xl[5]=t.xl[2],c.xl[6]=t.xl[5];return c;
}

唯一要主要的是ABC三种操作都是对xl进行的,但别忘记更新xu;

判重

读者一定用过set,其位于STL库中,功能十分强大,是用来判重的最简单方式,但时间效率比较低下,因此哈希技术更好一些,我们选用STL中的unordered_set,它使用哈希表实现,更适合此题目

if (pc.count(l)==0) {pc.emplace(l);return true;}

简单理解就是:
count(l):返回容器中值为 l 的元素数,如果容器中不存在值为 l 的元素,则返回 0。
emplace(l):向容器中添加新元素,传入的参数会被作为元素值进行插入操作,如果容器中已经存在相同元素,则什么也不做。
作用便是判重

end

读者都做到此题了,相信有能力自己理解bfs函数,笔者在这里不过多赘述,对于unordered_set,其还包括许多成员函数,可以在网络上搜索,了解相关内容。

[USACO3.2]魔板 Magic Squares相关推荐

  1. 魔板 Magic Squares(bfs优化)

    [USACO3.2]魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题 ...

  2. P2730 魔板 Magic Squares

    不看题解肯定不会系列... 这道题可以用Cantor展开解决. Cantor展开可以求出一个数组是在全排列中的第几个. 具体怎么操作自己百度. Cantor展开的公式是:\(a[1] * (n - 1 ...

  3. 洛谷P2730 [IOI]魔板 Magic Squares

    题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...

  4. P2730 魔板 Magic Squares (搜索)

    题目链接 Solution 这道题,我是用 \(map\) 做的. 具体实现,我们用一个 \(string\) 类型表示任意一种情况. 可以知道,排列最多只有 \(8!\) 个. 然后就是直接的广搜了 ...

  5. Magic Squares 魔板 (BFS+HASH)

    Description 在成功地发明了魔方之后,拉比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 我们知道魔板的每一个方格都有一种颜色.这8 ...

  6. USACO 3.2 Magic Squares 魔板

    题目大意: 在成功地发明了魔方之后,拉比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 我们知道魔板的每一个方格都有一种颜色.这8种颜色用前8 ...

  7. java51游戏_Java作业实践(一)魔板游戏

    课题:魔板游戏 一.课设要求 1.基本功能 (1)游戏规则 一个3×3的魔板,有一个格子是空的,其他格子内随机放置1-8共8个编号的方块,通过单击任意一个与空格子相邻的方块可以把该方块移入空格子,不断 ...

  8. 【题解】Luogu P2730 魔板

    蒟蒻的第一道蓝题--好像也没有蓝的程度 一篇无STL的超弱题解(入门写法无误了QAQ 传送门 很经典的一道BFS 这是初始状态. 操作A 操作B 操作C 思路1 不使用cantor展开的情况 1. 对 ...

  9. HDU 1430 魔板(康托展开+BFS+预处理)

    魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submis ...

最新文章

  1. 24 个你应该了解的 PHP 库
  2. 大物实验总结模板_高考化学实验题答题模板归类总结!
  3. ABP官方文档翻译 0.0 ABP官方文档翻译目录
  4. boost::geometry模块测试地理策略Testing geographic strategies的测试程序
  5. 业务决定功能,功能决定技术
  6. 设计模式 之 《组合模式》
  7. ORACLE监听问题
  8. _java等领域_测试、集成等领域最好的Java工具
  9. 【转】ARM汇编伪指令介绍
  10. 安装ESXI 5.5卡在LSI_MR3.V00解决方案
  11. 2020年 Java开发者进阶手册.pdf(吐血整理)
  12. LayaAir Geolocation 获取地理位置
  13. [解决方案]word文档无法存放过长过大的visio图片
  14. 暴力破解-----token验证
  15. 新电视显示服务器失败,电视网络连接失败原因是什么
  16. Tiny6410 初体验
  17. 009-Dockerfile-MAINTAINER(deprecate)-使用 LABEL 代替
  18. 接口测试、接口协议以及常用接口测试工具介绍
  19. 安装mysql的初始密码在哪里
  20. linux内核学习的屠龙刀、倚天剑(需要搭配硬件调试环境)

热门文章

  1. ntpd与ntpdate
  2. 软件工程毕业设计 SSM留学生交流平台系统(源码+论文)
  3. STM32使用大彩屏程序总结(一)
  4. 小孩子用什么台灯比较好?2023真正适合孩子的护眼台灯盘点
  5. Python爬虫基础操作二
  6. 大数据系统架构-MPP数据库架构
  7. 打开即用Chat gpt
  8. centos7建立局域网yum源
  9. Car-eye 主动安全车载管理平台对外接口
  10. vue里面怎么实现页面跳转_vue页面跳转如何实现 vue页面跳转实现代码