题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4531
吉哥系列故事——乾坤大挪移
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 555 Accepted Submission(s): 178
Problem Description
只有进入本次马拉松复赛,你才有机会知道一个秘密:吉哥的真名叫基哥,江湖人称“叽叽哥”。
叽叽哥除了编程,还一直有个武侠梦,他最喜欢的人物是金庸小说《倚天屠龙记》中的张无忌,不仅有美人环绕,而且有一身的好武功,尤其是那神秘的乾坤大挪移,让他梦寐以求:
“乾坤大挪移乃在颠倒一刚一柔、一阴一阳的乾坤二气,随意而行,不用心而无不心用,所谓至我逍遥游,以纯阳之身,和纯阴之体,合练双修,不动身,只用意,意动身守......”
但是,梦毕竟只是梦,平时在编程的空闲时间,叽叽哥也最多只能上网玩一下名为“乾坤大挪移”的游戏聊以自慰而已。
这个“乾坤大挪移”游戏是在3*3的方格中进行。
游戏的目标是通过移动,让相同颜色的块形成一个连通块(相邻是指两个块有边相邻,角相邻不算)。
移动规则如下:选择一行(列),向左右(上下)移动一格,方格从一边划出,则从对应的另外一边划入,像履带一样。
如选择第一行向右边移动,最右边的那格会移动到最左边。
游戏中还有一些方格被固定住,这些方格没办法移动(如下图的第三行第二列)。
下图是游戏的一个演示(即Case 1):
假设现在告诉你初始状态,请问你最少需要几步才能达到目标?
叽叽哥除了编程,还一直有个武侠梦,他最喜欢的人物是金庸小说《倚天屠龙记》中的张无忌,不仅有美人环绕,而且有一身的好武功,尤其是那神秘的乾坤大挪移,让他梦寐以求:
“乾坤大挪移乃在颠倒一刚一柔、一阴一阳的乾坤二气,随意而行,不用心而无不心用,所谓至我逍遥游,以纯阳之身,和纯阴之体,合练双修,不动身,只用意,意动身守......”
但是,梦毕竟只是梦,平时在编程的空闲时间,叽叽哥也最多只能上网玩一下名为“乾坤大挪移”的游戏聊以自慰而已。
这个“乾坤大挪移”游戏是在3*3的方格中进行。
游戏的目标是通过移动,让相同颜色的块形成一个连通块(相邻是指两个块有边相邻,角相邻不算)。
移动规则如下:选择一行(列),向左右(上下)移动一格,方格从一边划出,则从对应的另外一边划入,像履带一样。
如选择第一行向右边移动,最右边的那格会移动到最左边。
游戏中还有一些方格被固定住,这些方格没办法移动(如下图的第三行第二列)。
下图是游戏的一个演示(即Case 1):
假设现在告诉你初始状态,请问你最少需要几步才能达到目标?
Input
第一行一个整数T代表接下去有T组数据;
每组数据由3*3的模块组成,每个模块表示的小正方形是由上下左右四个小三角形组成;
每个模块有5个字符,前四个字符分别表示组成正方形的上下左右四个小三角形的颜色,第五个字符表示该格子能否移动(0表示能移动,1表示不能移动).
[Technical Specification]
0<T<=100
代表颜色的字符一定是RGBO的其中一个
代表能否移动移动的字符一定是0或者1
每组数据由3*3的模块组成,每个模块表示的小正方形是由上下左右四个小三角形组成;
每个模块有5个字符,前四个字符分别表示组成正方形的上下左右四个小三角形的颜色,第五个字符表示该格子能否移动(0表示能移动,1表示不能移动).
[Technical Specification]
0<T<=100
代表颜色的字符一定是RGBO的其中一个
代表能否移动移动的字符一定是0或者1
Output
首先输出case数,接着输出最小的移动步数使得游戏达到目标状态(见sample);
数据保证有解。
数据保证有解。
Sample Input
2 GGGG0 GGGG0 GGGG0 OGOO0 GGGG0 OGOO0 OOOO0 OGGG1 OOOO0 RRRR0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 RRRR0
Sample Output
Case #1: 5 Case #2: 2
Source
看到题目,确实感觉有点麻烦,很考验代码能力,代码能力差的话可能要写很长的代码,容易犯错。
首先类似于八数码问题的棋盘规格,我们考虑使用康拓展开作为状态压缩标记走过的棋盘样式,最多9!种状态。
节点保存棋盘压缩值,步数,棋盘样式。为了方便将每个方格内的四个三角分别对应0,1,2,3,那么a[i][j][k]就可以方便的表示i行j列第k个三角。
每次检查当前头部节点对应的棋盘是否达到了目标状态。这个听别人用的并查集,我没有用,我是dfs染色统计每个颜色联通快的个数,如果每个颜色的个数都<=1,说明当前就是一个合法的状态。关键就是dfs时的方向问题困扰了我,我们常见的方形棋盘一般就是4/8个直观的方形,这个却是三角,其实也不是很难,我们只要dfs三角形的三条边不就好了吗,一共四种三角分类讨论一下也就好了。最后就是有12种移动方式,简单的交换一下就好了,注意提前判断一下是否有不可移动的格子。
1 #include<bits/stdc++.h> 2 using namespace std; 3 bool vis[3630000]; 4 int f[15]={1,1,2,6,24,120,720,5040,40320,362880}; 5 struct node 6 { 7 int cal,bs; 8 char e[10]; 9 }; 10 void change1(node &t,int type) 11 { 12 switch(type) 13 { 14 case 1:swap(t.e[0],t.e[1]);swap(t.e[1],t.e[2]);break; 15 case 2:swap(t.e[1],t.e[2]);swap(t.e[0],t.e[1]);break; 16 case 3:swap(t.e[3],t.e[4]);swap(t.e[4],t.e[5]);break; 17 case 4:swap(t.e[4],t.e[5]);swap(t.e[3],t.e[4]);break; 18 case 5:swap(t.e[6],t.e[7]);swap(t.e[7],t.e[8]);break; 19 case 6:swap(t.e[7],t.e[8]);swap(t.e[6],t.e[7]);break; 20 case 7:swap(t.e[0],t.e[3]);swap(t.e[3],t.e[6]);break; 21 case 8:swap(t.e[3],t.e[6]);swap(t.e[0],t.e[3]);break; 22 case 9:swap(t.e[1],t.e[4]);swap(t.e[4],t.e[7]);break; 23 case 10:swap(t.e[4],t.e[7]);swap(t.e[1],t.e[4]);break; 24 case 11:swap(t.e[2],t.e[5]);swap(t.e[5],t.e[8]);break; 25 case 12:swap(t.e[5],t.e[8]);swap(t.e[2],t.e[5]);break; 26 } 27 28 } 29 int cal(node A) 30 { 31 int s=0,i,j; 32 for(i=0;i<9;++i) 33 { 34 int c=0; 35 for(j=i+1;j<9;++j) 36 if(A.e[j]<A.e[i]) c++; 37 s+=c*f[8-i]; 38 } 39 return s; 40 } 41 struct nic 42 { 43 char color[5]; 44 }a[4][4],b[4][4]; 45 bool mov[2][4]; 46 bool book[5][5][5]; 47 void dfs(int x,int y,int is,char clo) 48 { 49 if(x<1||y<1||x>3||y>3||is<0||is>3||b[x][y].color[is]!=clo||book[x][y][is]) return; 50 b[x][y].color[is]='X'; 51 book[x][y][is]=1; 52 if(is==0){ 53 dfs(x-1,y,2,clo); 54 dfs(x,y,1,clo); 55 dfs(x,y,3,clo); 56 } 57 else if(is==1){ 58 dfs(x,y+1,3,clo); 59 dfs(x,y,0,clo); 60 dfs(x,y,2,clo); 61 } 62 else if(is==2){ 63 dfs(x+1,y,0,clo); 64 dfs(x,y,1,clo); 65 dfs(x,y,3,clo); 66 } 67 else{ 68 dfs(x,y-1,1,clo); 69 dfs(x,y,0,clo); 70 dfs(x,y,2,clo); 71 } 72 } 73 bool ok(node A) 74 { 75 int G=0,B=0,R=0,O=0,i,j,k,p=0; 76 for(i=1;i<=3;++i) 77 for(j=1;j<=3;++j,p++){ 78 int di=((int)(A.e[p]-'0'))/3+1,dj=((int)(A.e[p]-'0'))%3+1; 79 for(k=0;k<4;++k) 80 b[i][j].color[k]=a[di][dj].color[k]; 81 } 82 for(i=1;i<=3;++i) 83 for(j=1;j<=3;++j) 84 for(k=0;k<4;++k) 85 { 86 if(b[i][j].color[k]=='G') 87 {G++;} 88 else if(b[i][j].color[k]=='B') 89 B++; 90 else if(b[i][j].color[k]=='R') 91 R++; 92 else if(b[i][j].color[k]=='O') 93 O++; 94 else continue; 95 memset(book,0,sizeof(book)); 96 dfs(i,j,k,b[i][j].color[k]); 97 } 98 return (G<=1&&B<=1&&R<=1&&O<=1); 99 } 100 int bfs() 101 { 102 queue<node>Q; 103 memset(vis,0,sizeof(vis)); 104 node t1,t2; 105 t1.cal=0; 106 t1.bs=0; 107 strcpy(t1.e,"012345678"); 108 ok(t1); 109 Q.push(t1); 110 while(!Q.empty()){ 111 t1=Q.front();Q.pop(); 112 if(ok(t1)) {return t1.bs;} 113 if(vis[t1.cal]) continue; 114 vis[t1.cal]=1; 115 for(int i=1;i<=12;++i) 116 { 117 if(i<=6&&mov[0][(i+1)/2]) continue; 118 if(i>6&&mov[1][(i+1)/2-3]) continue; 119 node tmp=t1; 120 tmp.bs++; 121 change1(tmp,i); 122 tmp.cal=cal(tmp); 123 if(!vis[tmp.cal]) Q.push(tmp); 124 } 125 } 126 return -1; 127 } 128 int main() 129 { 130 int T,N,M,i,j,cas=0,n,m,k; 131 int index[4]={0,2,3,1}; 132 cin>>T; 133 while(T--){ 134 memset(mov,0,sizeof(mov)); 135 memset(a,0,sizeof(a)); 136 for(i=1;i<=3;++i) 137 for(j=1;j<=3;++j) 138 { 139 for(k=0;k<4;++k) 140 cin>>a[i][j].color[index[k]]; 141 scanf("%d",&m); 142 if(m==1) mov[0][i]=mov[1][j]=1; 143 } 144 printf("Case #%d: %d\n",++cas,bfs()); 145 } 146 return 0; 147 }