哈希+Bfs【P2730】 魔板 Magic Squares
没看过题的童鞋请去看一下题-->P2730 魔板 Magic Squares
不了解康托展开的请来这里-->我这里
至于这题为什么可以用康托展开?(瞎说时间到.
因为只有8个数字,且只有1~8这8个数字,所以我们可以算出最多情况有8!=40320个.
所以我们完全可以开数组记录这些状态并且记录这些答案.
康托展开的作用就是把这些排列映射成一个排名.
如果我们存储排列,那极限情况应该是87654321,很容易就炸掉的.
而映射成排名的话,我们开的极限只有40320,大约是1/2173的空间.
因此我们就可以这样去存储状态.
即
vis[i]代表排名为i的排列存在
to[i]代表从初状态到达排名为i的状态的操作序列.//要开成string类型.
求解:
那么如何求解呢?
对于初状态{1,2,3,4,5,6,7,8}是不变的,因此我们可以用bfs预处理出来其他状态.
而要满足字典序最小,我们可以先尝试进行A操作,B操作,C操作即可。其他操作就和普通的bfs差不多了。
对操作之后的序列,我们去求一下他的排名,那我们就可以得到 变成他的操作序列.把操作序列存储进to[]数组即可。
ps:字符串string类型支持拼接操作
而我们不要忘记把序列还原。
即改变一个序列有三种操作,我们不能连续进行A,B,C操作,需要对当前的序列操作.
因此就预处理出来了。
解决:
然后我们如何输入?(这里卡了好久的QwQ
getchar()可以读一切字符(应该是
所以我们就可以每次放一个getchar()!
而去一位一位的存储读入的字符串。
所以说我们就可以完美的解决这个题啦!
部分代码参考-->@qiqi_starsky
-------------------代码---------------------
#include<bits/stdc++.h>
#define IL inline
#define RI register int
using namespace std;
const int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//阶乘
struct code
{
string st,step;
}s,ss;
string to[666666];
bool vis[666666];
IL int Contor(string &s)//这里本应该不加&就可以正确的.
//但不加会Wa
//应该是你谷评测机的锅.
//已经尝试过在bzoj提交,不加&是可以过的
{
int ans=0;
for(RI i=0;i<8;i++)
{
//std::cout<<ans<<std::endl;
int smaller=0;
for(RI j= i+1 ;j<8;j++)
{
if(s[i] > s[j])smaller++;
}
ans += smaller*fac[8-i-1];
}
return ans+1;
}
IL void A(string &s)
{
for(RI i=0;i<4;i++)
swap(s[i],s[8-i-1]);
}
IL void B(string &s)
{
int t=s[3];
for(RI i=3;i>=1;i--)
s[i]=s[i-1];
s[0]=t;
int tt=s[4];
for(RI i=4;i<=6;i++)
s[i]=s[i+1];
s[7]=tt;
}
IL void C(string &s)
{
int t=s[6];
s[6]=s[5];
s[5]=s[2];
s[2]=s[1];
s[1]=t;
}
/*
1 2 3 4
5 6 7 8
↓ ↓ ↓ ↓
1 7 2 4
8 6 3 5
*/
IL void bfs()
{
std::queue<code>q;
s.st="12345678";
s.step="";
q.push(s);
vis[Contor(s.st)]=true;
while(!q.empty())
{
s=q.front();q.pop();
ss=s;
A(ss.st);//A操作
int cnt=Contor(ss.st);//对于改变的操作序列求出他的排名
if(!vis[cnt])
{
ss.step+="A";
to[cnt]=ss.step;//字符串可以直接整个赋过去
q.push(ss);//把一个新的字符串放过去,接下来扩展
vis[cnt]=true;//标记
}
ss=s;//还原的操作!!!很重要!
B(ss.st);//B操作
cnt=Contor(ss.st);
if(!vis[cnt])
{
ss.step+="B";
to[cnt]=ss.step;
q.push(ss);
vis[cnt]=true;
}
ss=s;
C(ss.st);//C操作
cnt=Contor(ss.st);
if(!vis[cnt])
{
ss.step+="C";
to[cnt]=ss.step;
q.push(ss);
vis[cnt]=true;
}
}
}
int main()
{
bfs();
string str;
cin>>str[0];getchar();cin>>str[1];getchar();
cin>>str[2];getchar();cin>>str[3];getchar();
cin>>str[4];getchar();cin>>str[5];getchar();
cin>>str[6];getchar();cin>>str[7];getchar();
//这输入厉害不厉害!
int cnt=Contor(str);
cout<<to[cnt].length()<<endl;//字符串用.length()
cout<<to[cnt]<<endl;
}
后话
如果给定的初始序列不是{1,2,3,4,5,6,7,8}怎么办?
把初始序列看成{1,2,3,4,5,6,7,8}即可
Upd
2018.09.03
回来填坑
当我们的初始序列不是{1,2,3,4,5,6,7,8}该怎么做?
例如: 瞎出的例子emmmm
初始状态:65783241——>12345678
对应位置得到这种状态↓
终止状态:13486572——>85741236
更详细一点↓
看好如何对应。
初状态 6 5 7 8 3 2 4 1
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
对应为 1 2 3 4 5 6 7 8
即我们要把想得到的状态
1 3 4 8 6 5 7 2
用上面的对应关系转化
过程↓
1 发现 1->8
3 发现 3->5
4 发现 4->7
8 发现 8->4
6 发现 6->1
5 发现 5->2
7 发现 7->3
2 发现 2->6
最终得到8 5 7 4 1 2 3 6
如果不理解,请仔细再看一下。
这样我们求解{6,5,7,8,3,2,4,1}到{1,3,4,8,6,5,7,2}的操作,
就转变为了{1,2,3,4,5,6,7,8}到{8,5,7,4,1,2,3,6}的操作.
代码实现转化↓(尝试理解一下,懒得码字了 emmm
for (int i=0; i<8 ; i++)
num[s[i]-'0']=i+1;
//看看我们的枚举,所以需要i+1得到1,2,3.....8
//get关系↑.s存储初状态
//转化关系↓.str存储末状态
for (int i=0; i<8 ; i++)
str[i]=num[str[i]-'0']+'0';
如果有新的知识,我还会来Upd的
(逃
Upd:
2018.09.05
关于康托展开那里的字符串是否需要加&不知道是否会有疑问?
感谢@cellur925
的提问
已经在bzoj尝试不加&,是可以AC的.
并通过在我谷下载数据并尝试debug,发现输出是一样的.
Contor函数并没有涉及到修改原串,因此不加&应该是正确的.
感觉应该是你谷评测机的锅
而其他A,B,C操作是需要修改原串的,需要加&.
PS:加&是可以引用变量的.
哈希+Bfs【P2730】 魔板 Magic Squares的更多相关文章
- 洛谷 P2730 魔板 Magic Squares 解题报告
P2730 魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 ...
- 洛谷 P2730 魔板 Magic Squares
P2730 魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 ...
- [洛谷P2730] 魔板 Magic Squares
洛谷题目链接:魔板 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都 ...
- P2730 魔板 Magic Squares
题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...
- 洛谷 - P2730 - 魔板 Magic Squares - bfs
写状态转移弄了很久,老了,不记得自己的数组是怎么标号的了. #include <bits/stdc++.h> using namespace std; #define ll long lo ...
- P2730 魔板 Magic Squares (搜索)
题目链接 Solution 这道题,我是用 \(map\) 做的. 具体实现,我们用一个 \(string\) 类型表示任意一种情况. 可以知道,排列最多只有 \(8!\) 个. 然后就是直接的广搜了 ...
- 【简●解】 LG P2730 【魔板 Magic Squares】
LG P2730 [魔板 Magic Squares] [题目背景] 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 ...
- [USACO3.2]魔板 Magic Squares
松下问童子,言师采药去. 只在此山中,云深不知处.--贾岛 题目:魔板 Magic Squares 网址:https://www.luogu.com.cn/problem/P2730 这是一张有8个大 ...
- 「一本通 1.4 例 2」[USACO3.2]魔板 Magic Squares
[USACO3.2]魔板 Magic Squares 题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题 ...
随机推荐
- strings用法小记
By francis_hao Feb 14,2017 打印文件中可打印字符,每个序列至少四(可配置)个字符长.主要用于显示非文本文件 概述 选项解释 -a --all - 扫描整个文件,不管 ...
- POJ2240:Arbitrage(最长路+正环)
Arbitrage Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 29374 Accepted: 12279 题目链接: ...
- 安卓sdk安装教程
http://blog.csdn.net/love4399/article/details/77164500
- angular的一些问题
引入第三方类库 1.安装依赖 npm install jquey --save 2.引入项目 在angular-cli.json "scripts": [ "../nod ...
- poj 2104 (主席树写法)
//求第K的的值 1 #include<stdio.h> #include<iostream> #include<algorithm> #include<cs ...
- java,jenkins
以前玩的是hudson ,现在玩的是jenkins.以前用的是Tomcat,现在不知道他们怎么不用... 1,装个Jenkins镜像. 2.配置项目: 先取个名字:exchange 配个svn: 构建 ...
- rsync 同步
1./usr/bin/rsync -vzrtopg --progress --include "weibo-service-server" --exclude "/*& ...
- Join to domain powershell script
Join to domain powershell script $username = "domain\admin" $Password = "xxxxxxxx&quo ...
- 【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组
http://poj.org/problem?id=1743 这题是一道后缀数组的经典例题:求不可重叠最长重复子串. 题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲 ...
- [BZOJ1026][SCOI2009]windy数 解题报告|数位dp
Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? 一直 ...