相信大家都玩过贪吃蛇游戏吧。
在n×m的迷宫中,有着一条长度不超过9的贪吃蛇,它已经将所有的食物吃光了,现在的目标是移动到出口。
它走的时候不能碰到自己的身体,也不能碰到墙壁。(如果贪吃蛇的长度>3并且下一步要走到自己的尾部,是合法的)
问它能不能走到出口,如果能,最少要移动几步?
数据包含多组数据,请读入到文件末尾EOF
每组数据第一行包含两个整数n,m(1≤n,m≤15)代表迷宫的大小。
接下来n行,每行包含一个长度为m的字符串,来表示迷宫。
字符串中仅包含.
、#
、@
、1
~ 9
、.
代表空地 #
代表墙 数字一定是1∼k 连续的k个数字,代表贪吃蛇,1代表它的头,k代表它的尾,数据保证数字i一定和数字i+1在迷宫中相邻。 @
代表出口。
对于每组数据,先输出Case #i:
,i为当前数据组数。
接下来一个数,代表贪吃蛇最少需要移动的步数,若无法移动出去输出-1
解题报告
主要是判重问题
肯定不能vis[15][15].....x9
内存依然爆炸,其实大部分都是没有使用的,因此我们考虑到
蛇的每截身体较于前面一截只有 4 种状态,我们用4进制来压缩蛇的身体,这样就能存下了,注意蛇头可以移动到最后一截身体所在的位置.
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int Max = 15; char G[Max+2][Max+2]; bool vis[15][15][9850]; int R,C,targetx,targety,n; // n is snake-body num int dir[4][2] ={-1,0,1,0,0,-1,0,1}; int caculate[8] ={1,3,9,27,81,243,729,2187}; typedef struct status { int x[9]; int y[9]; int step; }; status ori; status thisq[1000000]; int getturn(int x,int y,int x0,int y0){ if (x - x0 == 1) return 0; if (x - x0 == -1) return 1; if (y - y0 == 1) return 2; if (y - y0 == -1) return 3; printf("Error at get turn!\n"); } int getcode(status& x){ int buffer[12]; int code = 0; for(int i = 1;i<n;++i) code += getturn(x.x[i],x.y[i],x.x[i-1],x.y[i-1]) * caculate[i-1]; return code; } bool judge(status& x){ int tx = x.x[0]; int ty = x.y[0]; for(int i = 1;i<n;++i) if(x.x[i] == tx && x.y[i] == ty) return false; return true; } bool dfs1(int x,int y){ int front = 0,rear = 0; int q[8000][2]; bool evis[15][15]; memset(evis,false,sizeof(evis)); evis[x][y] = true; q[rear][0] = x; q[rear++][1] = y; while(front < rear) { int tx = q[front][0]; int ty = q[front++][1]; if (tx == targetx && ty == targety) return true; for(int i = 0;i<4;++i) { int newx = tx + dir[i][0]; int newy = ty + dir[i][1]; if (!evis[newx][newy] && G[newx][newy] != ‘#‘ && newx < R && newx >=0 && newy < C && newy >=0) { q[rear][0] = newx; q[rear++][1] = newy; evis[newx][newy] = true; } } } return false; } int dfs(){ int front = 0,rear = 0; ori.step = 0; thisq[rear++] = ori; vis[ori.x[0]][ori.y[0]][getcode(ori)] = true; while(front < rear) { int tx = thisq[front].x[0]; int ty = thisq[front].y[0]; int step = thisq[front].step; if (tx == targetx && ty == targety) return step; for(int i = 0 ;i < 4;++i) { int newx = tx + dir[i][0]; int newy = ty + dir[i][1]; int newstep = step+1; if (newx >= R || newx < 0 || newy >=C || newy < 0 || G[newx][newy] == ‘#‘) continue; status newst; newst.x[0] = newx; newst.y[0] = newy; newst.step = step + 1; for(int j=1;j<n;++j) { newst.x[j] = thisq[front].x[j-1]; newst.y[j] = thisq[front].y[j-1]; } if (!vis[newst.x[0]][newst.y[0]][getcode(newst)] && judge(newst)) { thisq[rear++] = newst; vis[newst.x[0]][newst.y[0]][getcode(newst)] = true; } } front++; } return -1; } bool input(){ while(scanf("%d%d%*c",&R,&C)==2) { n = 0; memset(vis,false,sizeof(vis)); for(int i = 0;i<R;++i) gets(&G[i][0]); for(int i = 0;i<R;++i) for(int j = 0;j<C;++j) if(G[i][j] == ‘@‘) { targetx = i; targety = j; } else if(G[i][j] <= ‘9‘ && G[i][j] >= ‘1‘) { ori.x[G[i][j] - ‘1‘] = i; ori.y[G[i][j] - ‘1‘] = j; n ++ ; } return true; } return false; } int main(int argc,char * argv[]){ int T = 1; while(input() == true) { if(!dfs1(ori.x[0],ori.y[0])) { cout << "Case #"<< T++ <<": -1" <<endl; continue; } int ans = dfs(); cout << "Case #"<< T++ <<": "<< ans <<endl; } return 0; }
原文:http://www.cnblogs.com/Xiper/p/4455053.html