HDU 1430 魔板(BFS+HASH+置换)
http://acm.hdu.edu.cn/showproblem.php?pid=1430
Problem Description
在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板。魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:
1 2 3 4
8 7 6 5
对于魔板,可施加三种不同的操作,具体操作方法如下:
A: 上下两行互换,如上图可变换为状态87654321
B: 每行同时循环右移一格,如上图可变换为41236785
C: 中间4个方块顺时针旋转一格,如上图可变换为17245368
给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。
Input
每组测试数据包括两行,分别代表魔板的初态与目态。
Output
对每组测试数据输出满足题意的变换步骤。
Sample Input
12345678
17245368
12345678
82754631
Sample Output
C
AC
分析:其实本题就是普通的BFS题目不过要用到HASH,这里还有一个关键点就是相对状态.
首先依然是用一个int来表示一个状态,其中st的每三位二进制值表示一个0-7的数.然后用HASH判重,且用到了置换的技巧(简化了代码,具体看源代码.当然不用置换数组op也行)
我们用BFS预处理求出了从初态01234567到任意状态的方案.但是题目假设给了我们初态:32107654
目态:01236547 .我们如何求呢?
我们只需要把32107654看成是01234567(或abcdefgh),然后转换出目态即可.
即:因为目态(01236547)的0在初态的第4个位置上,本来原始状态01234567中.第4个位置上的是3,所以目态的0应该变成3.依此类推.
最终目态code就会被看成是32105674.
网上还有将状态用康托展开编号的,其实并不需要这么麻烦.
AC代码:15ms
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int HASH=100007;
int op[3][8]=
{
{7,6,5,4,3,2,1,0},
{3,0,1,2,5,6,7,4},
{0,6,1,3,4,2,5,7}
};
struct HASHMAP
{
int head[HASH],next[HASH],st[HASH],size;
void init()
{
size=0;
memset(head,-1,sizeof(head));
}
int find(int _st)
{
int h=_st%HASH, u;
for(u=head[h];u!=-1;u=next[u])
if(st[u]==_st) break;
return u;
}
void insert(int _st)
{
int h=_st%HASH;
st[size]=_st;
next[size]=head[h];
head[h]=size++;
}
}hm;
int list[HASH],Q[HASH],code[8],pre[HASH];
void decode(int st)
{
for(int i=7;i>=0;i--) code[i]=st&7, st>>=3; //错误, 之前写成code[i]=st|7
}
int encode(int *code)
{
int st=0;
for(int i=0;i<8;i++) st= (st<<3)|code[i];
return st;
}
void BFS()
{
int front=0,tail=1;
for(int i=0;i<8;i++) code[i]=i;
int st=encode(code);
pre[0]=-1; Q[0]=st;
hm.init(); hm.insert(st); //错误,之前hm未初始化
while(front<tail)
{
st=Q[front];
decode(st);
for(int d=0;d<3;d++) //3种操作
{
int new_code[8];
for(int i=0;i<8;i++) new_code[i]=code[op[d][i]];
st=encode(new_code);
if(hm.find(st)==-1) //注意:这里Q队列和hm中的st状态下标是一一对应的
{
hm.insert(st);
list[tail]=d;
pre[tail]=front;
Q[tail++]=st;
}
}
front++;
}
}
void print(int pos)
{
if(pre[pos]>=0) //错误,之前写成pos>=0
{
print(pre[pos]);
printf("%c",list[pos]+'A');
}
}
int main()
{
BFS();
char a[10],b[10];
while(scanf("%s%s",a,b)==2)
{
int tran[10];
for(int i=0;i<8;i++) tran[a[i]-'1']=i;
for(int i=0;i<8;i++) code[i]=tran[b[i]-'1'];
int st=encode(code);
int pos=hm.find(st);
print(pos);
printf("\n");
}
return 0;
}
分享到:
相关推荐
Problem Description 话说,经过了漫长的一个多月,小明已经成长了许多,所以他改了一个名字叫“大明”。 这时他已经不是那个只会做100以内加法的那个“小明”了,现在他甚至会任意长度的正小数的加法。...
从简单入门到偏中等的几个题,线段树很灵活,主要懂了lazy操作,其他的自己yy吧。
本人准备2020年保研机试时刷的题目(虽然最后机试取消了,...来自某中流985,在HDU和vjudge平台上大概刷了400道。本文件地图(excel表格)包含了绝大部分我刷过的题目,笔记中具有思路、代码、总结和心得。 大佬勿入!
acm入门之枚举搜索,学校第一次acm培训,包括枚举及其优化,dfs和bfs
ACM题库,一些题目和答案,以及解题报告,传上来共享
hdu 3085 一道bfs题 一点值得注意的,鬼魅先走,mm与gg后走,直接模拟这个这个场景,突出时间的先后性,一秒与一秒的区别。。。这样模拟很难出错
杭电OnlineJudge 200-2099的解题报告
2、new做两件事,一是分配内存,二是调用类的构造函数 3、new建立的是一个对象,而malloc分配的是一块内存 4、new/delete是保留字,不需要头文
hdu 3341(ac自动机+状态压缩) 题意:容易理解... 思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A、T、C、G其中...
acm hdu as easy as a+b
hdu 1695 GCD(欧拉函数+容斥原理).docx
HDUACM2010版_14)Hash及应用HDUACM2010版_14)Hash及应用HDUACM2010版_14)Hash及应用HDUACM2010版_14)Hash及应用
300+ AC 代码 。 大数 , 线段树 , 字符串 , dp.....
HDU 1548 --- basic bfs 2. BNU 1440 --- basic dfs 3. POJ 1190 --- dfs + pruning(Strong) 4. UVALive 2243 --- dfs 5. FZU 2196 --- double bfs 6. PKU 1426 --- bfs + pruning 7. BNU 1038 --- dfs transform 8....
HDU的1250,主要是利用高精度加法,但是代码有点繁琐,效率不是很高
HDU1059的代码
杭电ACMhdu1163
hdu1001解题报告
hdu 1574 passed sorce