HDU 4531 吉哥系列故事——乾坤大挪移 (BFS)
吉哥系列故事——乾坤大挪移
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 184 Accepted Submission(s): 50
Problem Description
只有进入本次马拉松复赛,你才有机会知道一个秘密:吉哥的真名叫基哥,江湖人称“叽叽哥”。
叽叽哥除了编程,还一直有个武侠梦,他最喜欢的人物是金庸小说《倚天屠龙记》中的张无忌,不仅有美人环绕,而且有一身的好武功,尤其是那神秘的乾坤大挪移,让他梦寐以求:
“乾坤大挪移乃在颠倒一刚一柔、一阴一阳的乾坤二气,随意而行,不用心而无不心用,所谓至我逍遥游,以纯阳之身,和纯阴之体,合练双修,不动身,只用意,意动身守......”
但是,梦毕竟只是梦,平时在编程的空闲时间,叽叽哥也最多只能上网玩一下名为“乾坤大挪移”的游戏聊以自慰而已。
这个“乾坤大挪移”游戏是在3*3的方格中进行。
游戏的目标是通过移动,让相同颜色的块形成一个连通块(相邻是指两个块有边相邻,角相邻不算)。
移动规则如下:选择一行(列),向左右(上下)移动一格,方格从一边划出,则从对应的另外一边划入,像履带一样。
如选择第一行向右边移动,最右边的那格会移动到最左边。
游戏中还有一些方格被固定住,这些方格没办法移动(如下图的第三行第二列)。
下图是游戏的一个演示(即Case 1):
![](http://acm.hdu.edu.cn/data/images/4541-1.jpg)
假设现在告诉你初始状态,请问你最少需要几步才能达到目标?
叽叽哥除了编程,还一直有个武侠梦,他最喜欢的人物是金庸小说《倚天屠龙记》中的张无忌,不仅有美人环绕,而且有一身的好武功,尤其是那神秘的乾坤大挪移,让他梦寐以求:
“乾坤大挪移乃在颠倒一刚一柔、一阴一阳的乾坤二气,随意而行,不用心而无不心用,所谓至我逍遥游,以纯阳之身,和纯阴之体,合练双修,不动身,只用意,意动身守......”
但是,梦毕竟只是梦,平时在编程的空闲时间,叽叽哥也最多只能上网玩一下名为“乾坤大挪移”的游戏聊以自慰而已。
这个“乾坤大挪移”游戏是在3*3的方格中进行。
游戏的目标是通过移动,让相同颜色的块形成一个连通块(相邻是指两个块有边相邻,角相邻不算)。
移动规则如下:选择一行(列),向左右(上下)移动一格,方格从一边划出,则从对应的另外一边划入,像履带一样。
如选择第一行向右边移动,最右边的那格会移动到最左边。
游戏中还有一些方格被固定住,这些方格没办法移动(如下图的第三行第二列)。
下图是游戏的一个演示(即Case 1):
![](http://acm.hdu.edu.cn/data/images/4541-1.jpg)
假设现在告诉你初始状态,请问你最少需要几步才能达到目标?
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
Recommend
liuyiding
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4531
这题很明显就是bfs。
但是比赛的时候被坑死了,错了无数次。
用string就超时,只能改成char了,看来string慢很多啊。
我是用int表示状态的,初始状态就是012345678.这样用个map就可以对状态判重了。
至于判断是不是符合题意的状态,我用的是并查集来判断的。每个格子上下左右四个三角标号0、1、2、3.这样总共4*9=36个点。根据情况去合并,最后判断相同颜色是不是根相同即可。合并的时候,一个格子里的四条边可能合并,格子间12条边可能合并。
状态转移就是6种情况。分别对每一行、每一列操作。。
这题写挫了要么MLE,要么TLE,很难搞。。。。。。
/* *HDU 4531 *BFS *注意判重 */ #include <stdio.h> #include <string.h> #include <algorithm> #include <map> #include <set> #include <string> #include <queue> #include <iostream> using namespace std; char str[3][3][6]; char g[3][3][6]; map<int,int>mp; queue<int>q; bool move[6];//是否可以移动,0~5对应1~3行,1~3列 //并查集判断连通 int F[50]; int find(int x) { if(F[x]==-1)return x; return F[x]=find(F[x]); } void bing(int x,int y) { int t1=find(x); int t2=find(y); if(t1!=t2)F[t1]=t2; } //并查集判断是不是连通 bool judge(int state)//判断状态state是不是连通 { char temp[10]; int t[10]; sprintf(temp,"%09d",state); for(int i=0;i<9;i++)t[i]=temp[i]-'0'; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { int p=t[3*i+j]; int x=p/3; int y=p%3; strcpy(g[i][j],str[x][y]); } memset(F,-1,sizeof(F)); for(int i=0;i<3;i++) for(int j=0;j<3;j++) { if(g[i][j][0]==g[i][j][2])bing(12*i+4*j,12*i+4*j+2); if(g[i][j][0]==g[i][j][3])bing(12*i+4*j,12*i+4*j+3); if(g[i][j][1]==g[i][j][2])bing(12*i+4*j+1,12*i+4*j+2); if(g[i][j][1]==g[i][j][3])bing(12*i+4*j+1,12*i+4*j+3); } for(int i=0;i<3;i++) { if(g[i][0][3]==g[i][1][2])bing(12*i+3,12*i+4+2); if(g[i][1][3]==g[i][2][2])bing(12*i+4+3,12*i+8+2); } for(int j=0;j<3;j++) { if(g[0][j][1]==g[1][j][0])bing(4*j+1,12+4*j+0); if(g[1][j][1]==g[2][j][0])bing(12+4*j+1,24+4*j+0); } int R=-1,G=-1,B=-1,O=-1; for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<4;k++) { int t1=find(12*i+4*j+k); if(g[i][j][k]=='R') { if(R==-1)R=t1; else if(t1!=R)return false; } else if(g[i][j][k]=='G') { if(G==-1)G=t1; else if(t1!=G)return false; } else if(g[i][j][k]=='B') { if(B==-1)B=t1; else if(t1!=B)return false; } else { if(O==-1)O=t1; else if(t1!=O)return false; } } return true; } int bfs() { mp.clear(); while(!q.empty())q.pop(); int tmp,now; char ss1[10],ss2[10]; tmp=12345678; //初始是012345678 mp[tmp]=0; q.push(tmp); while(!q.empty()) { tmp=q.front(); q.pop(); if(judge(tmp))return mp[tmp]; sprintf(ss1,"%09d",tmp); for(int i=0;i<3;i++) for(int j=0;j<3;j++) { int t=ss1[3*i+j]-'0'; strcpy(g[i][j],str[t/3][t%3]); } //第一行的左右移动 if(move[0]) { strcpy(ss2,ss1); ss2[0]=ss1[1]; ss2[1]=ss1[2]; ss2[2]=ss1[0]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[0]=ss1[2]; ss2[1]=ss1[0]; ss2[2]=ss1[1]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } //第二行的左右移动 if(move[1]) { strcpy(ss2,ss1); ss2[3]=ss1[4]; ss2[4]=ss1[5]; ss2[5]=ss1[3]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[3]=ss1[5]; ss2[4]=ss1[3]; ss2[5]=ss1[4]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } //第三行的左右移动 if(move[2]) { strcpy(ss2,ss1); ss2[6]=ss1[7]; ss2[7]=ss1[8]; ss2[8]=ss1[6]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[6]=ss1[8]; ss2[7]=ss1[6]; ss2[8]=ss1[7]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } //第一列的左右移动 if(move[3]) { strcpy(ss2,ss1); ss2[0]=ss1[3]; ss2[3]=ss1[6]; ss2[6]=ss1[0]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[0]=ss1[6]; ss2[3]=ss1[0]; ss2[6]=ss1[3]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } //第二列的左右移动 if(move[4]) { strcpy(ss2,ss1); ss2[1]=ss1[4]; ss2[4]=ss1[7]; ss2[7]=ss1[1]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[1]=ss1[7]; ss2[4]=ss1[1]; ss2[7]=ss1[4]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } //第三列的左右移动 if(move[5]) { strcpy(ss2,ss1); ss2[2]=ss1[5]; ss2[5]=ss1[8]; ss2[8]=ss1[2]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } ss2[2]=ss1[8]; ss2[5]=ss1[2]; ss2[8]=ss1[5]; now=0; for(int i=0;i<9;i++) { now*=10; now+=ss2[i]-'0'; } if(mp.find(now)==mp.end()) { mp[now]=mp[tmp]+1; q.push(now); } } } return -1; } int main() { int T; scanf("%d",&T); int iCase=0; while(T--) { iCase++; printf("Case #%d: ",iCase); for(int i=0;i<6;i++)move[i]=true; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { scanf("%s",&str[i][j]); if(str[i][j][4]=='1')//所在的列和行不能移动 { move[i]=false; move[3+j]=false; } } printf("%d\n",bfs()); } return 0; }
人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想