bnuoj 1071 拼图++
问题描述
拼图玩具已经有约235年的历史了。早在1760年,法英两国几乎同时出现这种既流行又有益的娱乐方式。把一张图片粘在硬纸板上,然后把它剪成不规则小碎片。最初这些图片都是有教育意义的,要么附有适于年轻人阅读的短文,要么向新兴资产阶级传授历史或地理知识。
1762年,在法国路易十五统治时期,一个名叫迪马的推销商开始推销地图拼图,取得小小成功。这种地图拼图要求把碎片重新排列,是一种文雅的娱乐活动。同年,在伦敦,一位名叫约翰•斯皮尔斯伯里的印刷工也想到了相似的主意,发明了经久不衰的拼图玩具。他极其巧妙地把一幅英国地图粘到一张很薄的餐桌背面,然后沿着各郡县的边缘精确地把地图切割成小块。这一想法能带来巨额财富,但可怜的斯皮尔斯伯里并没有得到这笔钱,他只活了29岁,没能看到拼图玩具的巨大成功。他成功的真正意义在于,他为自己的发明打开了两个重要的市场:渴求知识的新兴中产阶级消费者,以及他所处时代严厉苛刻的英国学校。
现在很多手机、电子词典上都有这款游戏,一个很普遍的版本就是在一个3×3的方格中有8块1×1的图片块以及一个空格,通过移动这些被打乱的图块就能得到原图。
但是,这种类型的拼图却存在无解的情形,并且将近有一半的状态无解,这是YC不愿意看到的,他希望构造一种一定有解的拼图游戏。经过了N天的思考以后,他终于在原拼图游戏的基础上综合了一下魔方的玩法,总结出了一种新的玩法(也可能是老玩法,只是YC知识不够渊博没有发现……),玩法如下。
给出一个3×3的方格,其中有9块1×1的图片块,没有空格,每一次,玩家都能选取其中任意一个2×2的方格进行旋转,顺时针或者逆时针均可,但是每一次旋转只能旋转一格。YC把这个游戏告诉了WSY大牛,WSY大牛对这比较感兴趣,在那转啊转啊,可是却把自己弄晕了……(Orz……)于是,WSY大牛决定发挥CODER本色,编写一个程序,告诉他对于给定的任意一种起始图和目标图,最少需要多少次旋转。然后,他就可以向YC炫耀说他在多少步之内就解决了YC给他的问题。(YC不会问WSY大牛他是如何解出来的,因为YC对WSY大牛是膜拜状态……)
Input
第一行:一个整数K(K≤50),代表数据组数。
对于每一组数据:
第一行:9个整数,表示初始图形。
第二行:9个整数,表示目标图形。
每一组数据之前和之后都有一个空行。
9个整数范围都在1~9且不重复,出现顺序为3×3方格从最左上的方格开始,依次从左到右的、从上到下。
Output
对于每组数据,输出一行答案,即所需的最少步数,格式参照样例。
Sample Input
2 1 2 3 4 5 6 7 8 9 4 1 3 5 2 6 7 8 9 1 2 3 4 9 8 7 6 5 1 2 3 4 5 6 7 8 9
Sample Output
Number Of Move(s) Needed: 1 Number Of Move(s) Needed: 2
Hint
样例说明:
第一组:左上角顺时针旋转一次即可。
1 2 3 4 1 3
4 5 6 --> 5 2 6
7 8 9 7 8 9
第二组:右下角顺时针或者逆时针旋转两次均可。
顺:
1 2 3 1 2 3 1 2 3
4 9 8 --> 4 6 9 --> 4 5 6
7 6 5 7 5 8 7 8 9
逆:
1 2 3 1 2 3 1 2 3
4 9 8 --> 4 8 5 --> 4 5 6
7 6 5 7 9 6 7 8 9
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 int startS,endS; 7 const int MAXN=400000; 8 9 struct node 10 { 11 int s[3][3]; 12 int staus; 13 }; 14 int vis[MAXN];//标记 15 int fac[]={1,1,2,6,24,120,720,5040,40320,362880}; 16 17 int cantor(int s[3][3]) 18 { 19 int ans[10]; 20 int ll=0; 21 for(int i=0;i<3;i++) 22 { 23 for(int j=0;j<3;j++) 24 { 25 ans[ll++]=s[i][j]; 26 } 27 } 28 int sum=0; 29 for(int i=0;i<9;i++) 30 { 31 int num=0; 32 for(int j=i+1;j<9;j++) 33 if(ans[j]<ans[i])num++; 34 sum+=(num*fac[9-i-1]); 35 } 36 return sum+1; 37 } 38 39 void cpy(int a[][3],int b[][3]) 40 { 41 for(int i=0;i<3;i++) 42 { 43 for(int j=0;j<3;j++) 44 { 45 a[i][j]=b[i][j]; 46 } 47 } 48 } 49 50 void bfs() 51 { 52 int K[3][3]={{1,2,3},{4,5,6},{7,8,9}}; 53 memset(vis,-1,sizeof(vis)); 54 node p; 55 cpy(p.s,K); 56 p.staus=cantor(K); 57 queue<node>q; 58 vis[p.staus]=0; 59 while(!q.empty()) 60 q.pop(); 61 q.push(p); 62 while(!q.empty()) 63 { 64 p=q.front(); 65 q.pop(); 66 for(int i=0;i<2;i++) 67 { 68 for(int j=0;j<2;j++) 69 { 70 node temp1,temp2; 71 cpy(temp1.s,p.s); 72 int tmp; 73 tmp=temp1.s[i][j],temp1.s[i][j]=temp1.s[i][j+1],temp1.s[i][j+1]=temp1.s[i+1][j+1],temp1.s[i+1][j+1]=temp1.s[i+1][j],temp1.s[i+1][j]=tmp; 74 temp1.staus=cantor(temp1.s); 75 if(vis[temp1.staus]==-1) 76 { 77 vis[temp1.staus]=vis[p.staus]+1; 78 q.push(temp1); 79 } 80 cpy(temp2.s,p.s); 81 tmp=temp2.s[i][j],temp2.s[i][j]=temp2.s[i+1][j],temp2.s[i+1][j]=temp2.s[i+1][j+1],temp2.s[i+1][j+1]=temp2.s[i][j+1],temp2.s[i][j+1]=tmp; 82 temp2.staus=cantor(temp2.s); 83 if(vis[temp2.staus]==-1) 84 { 85 vis[temp2.staus]=vis[p.staus]+1; 86 q.push(temp2); 87 } 88 } 89 } 90 } 91 } 92 int main() 93 { 94 int t; 95 int S[10]; 96 int TT[3][3]; 97 scanf("%d",&t); 98 bfs(); 99 while(t--) 100 { 101 for(int i=1;i<=9;i++) 102 { 103 int a; 104 scanf("%d",&a); 105 S[a]=i; 106 } 107 for(int i=0;i<3;i++) 108 { 109 for(int j=0;j<3;j++) 110 { 111 int a; 112 scanf("%d",&a); 113 TT[i][j]=S[a]; 114 } 115 } 116 printf("Number Of Move(s) Needed: %d\n",vis[cantor(TT)]); 117 } 118 return 0; 119 }
此题比较裸的康拓展开,先BFS预处理出所有可能。
然后分别输入起始状态和最终状态。
对应预处理时的最初状态,相应的的根据起始状态将最终状态进行转化。
然后直接输出结果即可。。