这道题思路挺简洁的,但却绝对足够让我耳目一新了。
一、题意
学姐今晚想吃生鱼片, doc便领着她去吃啦. 但是怎么能这样轻易就让馋嘴的学姐吃到生鱼片呢!
于是doc准备了一个"二维魔方".
所谓 二维魔方, 可以被考虑为平面上 3X3 的方格, 里面不重复得填有 1~9 共9个数字.
每一次可以对某一行或某一列向某一方向做轮换操作, 比如说, 如果第三列原来的数字依次为 3 6 9, 那么针对第三列向上轮换一次后 就变成了: 6 9 3; 再向上轮换一次后 就变成了9 3 6.
现在doc给出了 二维魔方的初始状态, 再给出目标状态. 初始状态是由1~9组成的 3X3 的数字方格, 而目标状态中某个位置被标记为星号, 表示可以是任意数字.
如果学姐能用最少的操作次数得到目标状态, doc就会喂她吃一小块生鱼片呢!
第一行一个整数T, 表示总的询问次数.
之后有T次询问, 对于每一次询问, 有6行, 每行3组字符(包括数字1~9和星号)以空格隔开.
对于每一次询问, 输出一行.
首先输出询问的标号(参见样例输出), 之后输出最少的操作次数. 如果不可能做到, 输出"No Solution!"(不输出引号).
2
1 2 3
4 5 6
7 8 9
8 * 9
5 3 7
2 * *
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 9 8
Case #1: 7
Case #2: No Solution!
对于30%的数据, T <= 3
对于60%的数据, T <= 100
对于100%的数据, T <= 1000
二、题解
看到它我起初完全没有思路,只能暴搜,然后看了看题解,题解就一句话:一遍预处理BFS。
什么玩意儿!完全看不懂,啥叫一遍预处理?咋预处理啊?它初始状态和目标状态全不一样啊!
然后我问了ljs学长,终于搞明白了。。
学长说:虽然这么多初始状态,但是它们本质上都是一样的!
原来虽然这么多初始状态是不一样的,但是我们可以都将其映射到某一特定排列,例如123456789,然后令目标状态以同样的方式映射即可。这样的话,就把多源最短路优化成了单源最短路 !
做到这里,不仅想到约瑟夫问题和地精部落,同样是1~N的排列,同样的思想,同样的神奇!
①排列是可以离散的!在以后的学习中,处理排列问题时我想我必须牢牢记住这一点;在排列问题中,离散排列总是具有化腐朽为神奇的力量。
三、BFS中的代码技巧
1、用循环和函数来代替繁杂的拓展过程;
2、用交换来代替题意中蛋疼的旋转魔方。
3、②千万不要忘记回溯!随时思考变量的意义!
4、③如果写代码过程中突然想到了某些优化或更改,最好把它写下来;否则很可能改了这边忘了那边,导致程序出现差错。
5、④不要忘了编制数据和对拍。数据和代码一样重要!
#include<iostream> using namespace std; #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> char * ptr=(char *)malloc(100000); inline void in(int &x){ <span style="white-space:pre"> </span>while(*ptr<'0'||*ptr>'9')++ptr; <span style="white-space:pre"> </span>x=0; <span style="white-space:pre"> </span>while(*ptr>47&&*ptr<58)x=x*10+*ptr++-'0'; } #define J9 362880 int q[J9][9]={1,2,3,4,5,6,7,8,9},ni[]={1,1,2,6,24,120,720,5040,40320},dis[J9],ans[J9],h,t,Ans; bool p[J9],tmp[10]; int kangtuo(int a[]){ <span style="white-space:pre"> </span>bool p[10]; <span style="white-space:pre"> </span>int sum,ans=0,i,j; <span style="white-space:pre"> </span>memset(p,1,sizeof(p)); <span style="white-space:pre"> </span>for(i=0;i<9;++i){ <span style="white-space:pre"> </span>sum=0; <span style="white-space:pre"> </span>for(j=1;j<a[i];++j) <span style="white-space:pre"> </span>sum+=p[j]; <span style="white-space:pre"> </span>ans+=sum*ni[8-i]; <span style="white-space:pre"> </span>p[a[i]]=0; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>return ans; } inline void add(int a[]){ <span style="white-space:pre"> </span>int kt=kangtuo(a); <span style="white-space:pre"> </span>if(p[kt])return; <span style="white-space:pre"> </span>p[kt]=1; <span style="white-space:pre"> </span>memcpy(q[t],a,9*sizeof(int)); <span style="white-space:pre"> </span>dis[t]=dis[h]+1; <span style="white-space:pre"> </span>ans[kt]=dis[t++]; } inline void build(int x){ <span style="white-space:pre"> </span>if(x==9){ <span style="white-space:pre"> </span>Ans=min(Ans,ans[kangtuo(q[0])]); <span style="white-space:pre"> </span>return; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>if(q[0][x]+1)build(x+1); <span style="white-space:pre"> </span>else{ <span style="white-space:pre"> </span>for(int i=1;i<10;++i) <span style="white-space:pre"> </span>if(!tmp[i]){ <span style="white-space:pre"> </span>q[0][x]=i; <span style="white-space:pre"> </span>tmp[i]=1; <span style="white-space:pre"> </span>build(x+1); <span style="white-space:pre"> </span>tmp[i]=0; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>q[0][x]=-1; <span style="white-space:pre"> </span>} } inline void inchr(int &x){ <span style="white-space:pre"> </span>while((*ptr<'0'||*ptr>'9')&&*ptr!='*')++ptr; <span style="white-space:pre"> </span>x=*ptr=='*'?-1:*ptr-'0'; <span style="white-space:pre"> </span>++ptr; } int main(){ <span style="white-space:pre"> </span>int i,kt,X,T; <span style="white-space:pre"> </span>/*------Prework-----*/ <span style="white-space:pre"> </span>memset(ans,127,sizeof(ans)); <span style="white-space:pre"> </span>t=1; <span style="white-space:pre"> </span>kt=kangtuo(q[0]); <span style="white-space:pre"> </span>p[kt]=1; <span style="white-space:pre"> </span>ans[kt]=0; <span style="white-space:pre"> </span>for(h=0;h!=t;++h){ <span style="white-space:pre"> </span>/*--Change in row---*/ <span style="white-space:pre"> </span>for(i=3,X=1;i--;X+=3){ <span style="white-space:pre"> </span>swap(q[h][X-1],q[h][X+1]); <span style="white-space:pre"> </span>/*---Direction I--*/ <span style="white-space:pre"> </span>swap(q[h][X-1],q[h][X]); <span style="white-space:pre"> </span>add(q[h]); <span style="white-space:pre"> </span>swap(q[h][X-1],q[h][X]); <span style="white-space:pre"> </span>/*---Direction II--*/ <span style="white-space:pre"> </span>swap(q[h][X],q[h][X+1]); <span style="white-space:pre"> </span>add(q[h]); <span style="white-space:pre"> </span>swap(q[h][X],q[h][X+1]); <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>swap(q[h][X-1],q[h][X+1]); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>/*--Change in line---*/ <span style="white-space:pre"> </span>for(i=3,X=3;i--;++X){ <span style="white-space:pre"> </span>swap(q[h][X-3],q[h][X+3]); <span style="white-space:pre"> </span>/*---Direction I--*/ <span style="white-space:pre"> </span>swap(q[h][X-3],q[h][X]); <span style="white-space:pre"> </span>add(q[h]); <span style="white-space:pre"> </span>swap(q[h][X-3],q[h][X]); <span style="white-space:pre"> </span>/*---Direction II--*/ <span style="white-space:pre"> </span>swap(q[h][X],q[h][X+3]); <span style="white-space:pre"> </span>add(q[h]); <span style="white-space:pre"> </span>swap(q[h][X],q[h][X+3]); <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>swap(q[h][X-3],q[h][X+3]); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>/*--Read and Work Out--*/ <span style="white-space:pre"> </span>fread(ptr,1,100000,stdin); <span style="white-space:pre"> </span>in(T); <span style="white-space:pre"> </span>int point[10]; <span style="white-space:pre"> </span>bool flag; <span style="white-space:pre"> </span>for(int k=1;k<=T;++k){ <span style="white-space:pre"> </span>memset(tmp,0,sizeof(tmp)); <span style="white-space:pre"> </span>for(i=1;i<10;++i){ <span style="white-space:pre"> </span>inchr(X); <span style="white-space:pre"> </span>point[X]=i; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>flag=1; <span style="white-space:pre"> </span>for(i=0;i<9;++i,++ptr){ <span style="white-space:pre"> </span>inchr(q[0][i]); <span style="white-space:pre"> </span>if(q[0][i]+1){ <span style="white-space:pre"> </span>flag=0; <span style="white-space:pre"> </span>q[0][i]=point[q[0][i]]; <span style="white-space:pre"> </span>tmp[q[0][i]]=1; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>if(flag){ <span style="white-space:pre"> </span>printf("Case #%d: 0\n",k); <span style="white-space:pre"> </span>continue; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>Ans=0x7fffffff; <span style="white-space:pre"> </span>build(0); <span style="white-space:pre"> </span>printf("Case #%d: ",k); <span style="white-space:pre"> </span>if(Ans<100000000)printf("%d",Ans); <span style="white-space:pre"> </span>else printf("No Solution!"); <span style="white-space:pre"> </span>printf("\n"); <span style="white-space:pre"> </span>} }