hdu1430 魔板(双向bfs+输出路径+字典序最小)
来源:互联网 发布:日语翻译软件哪个好 编辑:程序博客网 时间:2024/04/29 20:40
魔板
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1352 Accepted Submission(s): 270
1 2 3 4
8 7 6 5
对于魔板,可施加三种不同的操作,具体操作方法如下:
A: 上下两行互换,如上图可变换为状态87654321
B: 每行同时循环右移一格,如上图可变换为41236785
C: 中间4个方块顺时针旋转一格,如上图可变换为17245368
给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。
12345678172453681234567882754631
CAC
题目分析:这题类似八数码,看完题分析了一下,8个位置每个位置9个状态,由于数字都不一样,判重用康托展开。
所以一共只有8!种状态,所以先拍了一个朴素的bfs,
结果华丽丽的TLE了,因为后台的case太多了。。单向不行那就双向吧。正好也练习一下双向bfs,
虽然这题只需要单向bfs预处理就可以很快过,但只是为了练习一下,
结果就走上了WA的不归路啊啊啊,整整跪了2天。最后感谢@FancyMouse 的帮助,找到了bug,终于过了啊啊啊啊。
这题双向bfs本来没那么复杂,不过要输出路径就有点复杂了,更dt的是还要字典序最小!!
方法是这样的,正向搜索很常规,直接搜就行了,按ABC依次扩展。flag[0][state]记录的是正向搜索从起点的
一条路径中state状态的前驱,那么op[0][state]记录的就是从state状态的前驱到state状态所用的操作。
反向也差不多,从终点依次向中间扩展,不过扩展的时候不是做相应的ABC操作,而是做ABC3种操作的逆操作,
即:A操作还是将字符串翻转,B操作就是每行左移1格了,C操作是中间4个左旋1格,这样有什么好处呢,
我们发现最后正反双向搜索搜到重复节点的时候要输出路径,这样的话我们直接从相遇点依次扫到终点,
扫出来的路径就是正向操作的路径。比如从终点逆向扩展2步CA到达某个倒数第二步,那么正着看,
从这个倒数第二步通过正常的AC操作也是能到达终点的。所以op[1][state]记录的就是从终点反向
扩展到state状态所用的逆操作,其实正着看就是从state状态往终点走的下一步的正向操作也是op[1][state],
flag[1][state]就是记录的state状态往终态走的后继状态,这样就能保证前后
2半都是字典序最小(想一想,为什么)。但是每找到一个解,不着急输出,不要着急跳出循环,
而是还要继续比较一下。我就是因为这一点长跪不起,
一直WA,因为搜索的过程中会有多解,比如这题的BCCC和ABCA就是效果相同的操作。
如果2个解是aaabbb和bbbaaa,并且在反向搜索的时候找到解,那么反向因为保证了字典序最小了,
所以反向会先扩展到aaa,找到解,如果直接
break显然有问题,
因为显然这个字典序不一定是最小的,显然没有考虑到前半段的结果。所以我们
找到解后不着急跳出来,只要标记上就可以了,把同一层的搜完,选出字典序最小的作为最优解。
代码写的比较臭比较长,但是比较清晰。
详情请见代码:
#include <iostream>#include<cstdio>#include<queue>#include<cstring>using namespace std;const int N = 1000005;int flag[2][50000];char op[2][50000];long fac[] = {1,1,2,6,24,120,720,5040,40320,362880};struct node{ int step,val; char state[10];}ss,now,temp[N];int tmpnum;struct que{ struct node t[N]; int head,tail; void init() { head = tail = 0; } bool empty() { return tail == head; } struct node top() { return t[head]; } void push(struct node a) { t[tail] = a; tail ++; if(tail >= N) tail %= N; } void pop() { head ++; if(head >= N) head %= N; }}q[2];//queue<node>q[2];int contor(){ int i,j; long temp,num; num = 0; for(i = 0;i < 8;i ++) { temp = 0; for(j = i + 1;j < 8;j ++) if(ss.state[j] < ss.state[i]) temp ++; num += temp * fac[8 - i - 1]; } return num;}void change(int type){ int i; char c; switch(type) { case 1:for(i = 0;i < 4;i ++) { ss.state[i] ^= ss.state[7 - i]; ss.state[7 - i] ^= ss.state[i]; ss.state[i] ^= ss.state[7 - i]; } break; case 2:c = ss.state[3]; for(i = 3;i > 0;i --) ss.state[i] = ss.state[i - 1]; ss.state[i] = c; c = ss.state[4]; for(i = 4;i < 7;i ++) ss.state[i] = ss.state[i + 1]; ss.state[i] = c; break; case 3:c = ss.state[1]; ss.state[1] = ss.state[6]; ss.state[6] = ss.state[5]; ss.state[5] = ss.state[2]; ss.state[2] = c; break; }}void change2(int type){ int i; char c; switch(type) { case 1:for(i = 0;i < 4;i ++) { ss.state[i] ^= ss.state[7 - i]; ss.state[7 - i] ^= ss.state[i]; ss.state[i] ^= ss.state[7 - i]; } break; case 2:c = ss.state[0]; for(i = 0;i < 3;i ++) ss.state[i] = ss.state[i + 1]; ss.state[i] = c; c = ss.state[7]; for(i = 7;i > 4;i --) ss.state[i] = ss.state[i - 1]; ss.state[i] = c; break; case 3:c = ss.state[1]; ss.state[1] = ss.state[2]; ss.state[2] = ss.state[5]; ss.state[5] = ss.state[6]; ss.state[6] = c; break; }}char s1[10],s2[10];int end,start;char ans[50000];char tans[5000];char ttans[5000];int ansnum;void print(){ int i; int root = ss.val; int num = 0;tans[num ++] = op[0][ss.val]; while(root != start) { root = flag[0][root];tans[num ++] = op[0][root]; }int p = 0; for(i = num - 2;i >= 0;i --){ //printf("%c",ans[i]);ttans[p ++] = tans[i];} num = 0; root = ss.val;tans[num ++] = op[1][ss.val]; while(root != end) {root = flag[1][root]; tans[num ++] = op[1][root]; } for(i = 0;i < num - 1;i ++){ //printf("%c",ans[i]);ttans[p ++] = tans[i];}ttans[p] = '\0';if(ansnum){if(strcmp(ans,ttans) > 0)strcpy(ans,ttans);}elsestrcpy(ans,ttans);ansnum ++;//newans;}int main(){ int i,j; while(~scanf("%s%s",s1,s2)) { if(strcmp(s1,s2) == 0) { puts(""); continue; } q[0].init(); q[1].init();// while(!q[0].empty())// q[0].pop();// while(!q[1].empty())// q[1].pop(); memset(flag,-1,sizeof(flag)); memset(op,0,sizeof(op)); ss.step = 0; strcpy(ss.state,s1); start = contor(); ss.val = start; flag[0][start] = start; q[0].push(ss); strcpy(ss.state,s2); end = contor(); ss.val = end; flag[1][end] = end; q[1].push(ss); bool ok = false; i = 0;tmpnum = 0;ansnum = 0; while(!ok) { while(!q[0].empty() && q[0].top().step == i) { now = q[0].top(); q[0].pop(); ss = now; ss.step ++; change(1); ss.val = contor(); if(flag[0][ss.val] == -1) { flag[0][ss.val] = now.val; op[0][ss.val] = 'A'; if(flag[1][ss.val] != -1) { print(); ok = true; //break;//罪恶的break } q[0].push(ss); } ss = now; ss.step ++; change(2); ss.val = contor(); if(flag[0][ss.val] == -1) { flag[0][ss.val] = now.val; op[0][ss.val] = 'B'; if(flag[1][ss.val] != -1) { print(); ok = true; //break;//wa之源 } q[0].push(ss); } ss = now; ss.step ++; change(3); ss.val = contor(); if(flag[0][ss.val] == -1) { flag[0][ss.val] = now.val; op[0][ss.val] = 'C'; if(flag[1][ss.val] != -1) { print(); ok = true; //break;//冷静分析 } q[0].push(ss); } }if(ok)break; while(!q[1].empty() && q[1].top().step == i) {//先把同一层的一起出队,同时按ABC扩展,这样才能保证反向 temp[tmpnum ++] = q[1].top();//字典序最小, q[1].pop();//如果不能理解,用笔在纸上画画就明白了 } for(j = 0;j < tmpnum;j ++) { ss = temp[j]; ss.step ++; change2(1); ss.val = contor(); if(flag[1][ss.val] == -1) { flag[1][ss.val] = temp[j].val; op[1][ss.val] = 'A'; if(flag[0][ss.val] != -1) { print(); ok = true; // break;//break要三思 } q[1].push(ss); } } for(j = 0;j < tmpnum;j ++) { ss = temp[j]; ss.step ++; change2(2); ss.val = contor(); if(flag[1][ss.val] == -1) { flag[1][ss.val] = temp[j].val; op[1][ss.val] = 'B'; if(flag[0][ss.val] != -1) { print(); ok = true; // break;//早该想到的 } q[1].push(ss); } } for(j = 0;j < tmpnum;j ++) { ss = temp[j]; ss.step ++; change2(3); ss.val = contor(); if(flag[1][ss.val] == -1) { flag[1][ss.val] = temp[j].val; op[1][ss.val] = 'C'; if(flag[0][ss.val] != -1) { print(); ok = true; // break;//。。。。 } q[1].push(ss); } } tmpnum = 0; i ++;if(ok)break; } printf("%s\n",ans); } return 0;}//1234MS820K//625MS924K 好吧,g++提交时间快了一倍。。。/*12345678645728131234567874381652158746237384165212345678827546311234567848136275123456781234567812345678876543211234567841236785123456785876321412345678863542711234567858632714123456785186372412345678427368151763825446273185762538412638715413578642246875313671825482716435123456782134567846753812543876123752168454137628*/CSDN的排版怎么回事啊啊啊。。。。
- hdu1430 魔板(双向bfs+输出路径+字典序最小)
- bfs+预处理+路径回溯+字典序最小+hash
- hdu1430魔板(BFS+康托展开)
- hdu1430 魔板 (BFS+康托展开式)
- hdu 1385 floyd+最小字典序路径输出!!
- poj 1041(欧拉回路+输出字典序最小路径)
- hdoj 1385 输出 最短路的最小字典序路径
- hdu1430 (bfs)
- UVA 10537 The Toll! Revisited(最短路变形+输出字典序最小路径)
- uva 10537 - The Toll! Revisited (逆向思维+最短路+输出字典序最小路径)
- hdu 1814 Peaceful Commission (2-sat 输出字典序最小路径)
- hdu1385 Minimum Transport Cost (floyd输出字典序最小的路径)
- CCF送货 欧拉路的判断+Fleury算法输出欧拉路的字典序最小的路径
- 最短路+字典序最小+输出路径(Ideal Path,UVA 1599)
- hdu 1358 floyd+输出字典需最小最短路径
- hdu1430(康托展开+BFS)
- Floyd求字典序最小的路径
- 输出字典序最小的背包方案
- 记录使用JGraph过程中的点点滴滴
- [C#基础知识]HashMap与Hashtable的区别
- QT显示图片
- Qt中图像的显示与基本操作
- qtopia 例子
- hdu1430 魔板(双向bfs+输出路径+字典序最小)
- Template Method
- [C#基础知识]泛型Dictionary<string,string>的用法详解
- <html:select>
- Spring AOP 详解
- memcache必须掌握的知识点
- JAVA JDK path路径
- Flex特效
- 一个memcache的常用操作类