12345678 17245368 12345678 82754631
C AC
题目分析:这题类似八数码,看完题分析了一下,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); } else strcpy(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; } //1234MS 820K //625MS 924K 好吧,g++提交时间快了一倍。。。 /* 12345678 64572813 12345678 74381652 15874623 73841652 12345678 82754631 12345678 48136275 12345678 12345678 12345678 87654321 12345678 41236785 12345678 58763214 12345678 86354271 12345678 58632714 12345678 51863724 12345678 42736815 17638254 46273185 76253841 26387154 13578642 24687531 36718254 82716435 12345678 21345678 46753812 54387612 37521684 54137628 */CSDN的排版怎么回事啊啊啊。。。。