在一个棋盘上移动骰子,求最少次数使骰子移动一圈回到原点。移动有限制,顶面数字与目标格数字相同或目标格为-1时才可以移动。
输入棋盘和骰子的初始位置和初始状态(用顶面和正面表示)。
感觉与UVa816特别相似。因为有骰子朝向问题,所以还要注意顶面和正面的数字,所以要用四维数组vis记录当前状态是否出现过。
思路出来了代码实现就很简单了,从起点开始BFS,vis数组在判断是否出现的同时还要记录经过的步数,用state数组记录上一步的状态。
当再次遇到起点坐标时,打印解。
骰子的旋转移动事先打表。
PS:开始的时候CE了,cmath里有y0、y1的定义。std里有node关键字。
#include<cstdio> #include<cstring> #include<queue> #include<stack> #include<algorithm> using namespace std; const int maxn=12; const int ro1[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//骰子的移动打表。 const int ro2[7][7]={ {0,0,0,0,0,0,0}, {0,0,4,2,5,3,0}, {0,3,0,6,1,0,4}, {0,5,1,0,0,6,2}, {0,2,6,0,0,1,5}, {0,4,0,1,6,0,3}, {0,0,3,5,2,4,0} }; char s[25]; int r,c,x_sta,y_sta,u,f,g[maxn][maxn]; int vis[maxn][maxn][7][7]; struct Node{ int x,y,u,f; Node(int x=0,int y=0,int u=0,int f=0):x(x),y(y),u(u),f(f){} }; Node state[maxn][maxn][7][7]; bool read(){ if(scanf("%s",s)==EOF||!strcmp(s,"END")) return false; memset(g,0,sizeof(g)); scanf("%d%d%d%d%d%d",&r,&c,&x_sta,&y_sta,&u,&f); for(int i=1;i<=r;++i) for(int j=1;j<=c;++j) scanf("%d",&g[i][j]); return true; } Node rotate(Node pre,int dis){ Node cur=pre; cur.x+=ro1[dis][0],cur.y+=ro1[dis][1]; if(dis==0){cur.f=7-cur.f;swap(cur.u,cur.f);} if(dis==1){cur.u=7-cur.u;swap(cur.u,cur.f);} if(dis==2){cur.u=ro2[cur.u][cur.f];} if(dis==3){cur.u=7-ro2[cur.u][cur.f];} return cur; } bool match(Node cur,int i){ if(g[cur.x+ro1[i][0]][cur.y+ro1[i][1]]==-1) return true; if(g[cur.x+ro1[i][0]][cur.y+ro1[i][1]]==cur.u) return true; return false; } bool in(Node cur,int i){ return cur.x+ro1[i][0]>0&&cur.x+ro1[i][0]<=r&&cur.y+ro1[i][1]>0&&cur.y+ro1[i][1]<=c; } void print_ans(Node a){ stack<Node> Nodes;//倒着找到的解,所以要压入栈,然后倒着输出。 Nodes.push(Node(x_sta,y_sta,u,f)); while(1){ Nodes.push(a); if(!vis[a.x][a.y][a.u][a.f]) break; a=state[a.x][a.y][a.u][a.f]; } int cnt=0; while(1){ if(cnt%9==0) printf("\n "); printf("(%d,%d)",Nodes.top().x,Nodes.top().y); Nodes.pop(); if(!Nodes.empty()) printf(",");//格式控制。 else{ printf("\n"); break; } cnt++; } return; } void solve(){ printf("%s",s); memset(vis,-1,sizeof(vis)); memset(state,0,sizeof(state)); queue<Node> q; Node sta(x_sta,y_sta,u,f); vis[x_sta][y_sta][u][f]=0; q.push(sta); while(!q.empty()){ Node a=q.front(); q.pop(); for(int i=0;i<4;++i){ if(!match(a,i)||!in(a,i)) continue; Node b=rotate(a,i); if(b.x==x_sta&&b.y==y_sta){//找到就打印解。 print_ans(a); return; } if(vis[b.x][b.y][b.u][b.f]<0){ vis[b.x][b.y][b.u][b.f]=vis[a.x][a.y][a.u][a.f]+1;//记录步数。 state[b.x][b.y][b.u][b.f]=a;//记录上一步的位置和骰子状态。 q.push(b); } } } printf("\n No Solution Possible\n"); return; } int main(){ while(read()){ solve(); } return 0; }