uva 10047 The Monocycle
献上题意:个你一个转轮,有5种颜色,为了5中颜色的位置是确定的,为了方便处理我们用01234来表示绿,黑,红,蓝,白。轮子可以沿着它的方向滚动(只能是它当前的方向不能相反方向),每滚动一次会到达另一个格子,着地的颜色会改变,变了之前颜色的下一个,例如当前是绿色着地下一次就是黑色,依次是红蓝白。也可以原地转动(顺逆时针都可以),原地转动其实就是改变了轮子的滚动方向,原地转动每次能转90度。原地转动一次和滚动一次时间都是1秒。另外轮子有4个方向,上北下南左西又东。
另外给你n*m个格子,有些格子不能到达,用#表示,给你起点S和终点T。在起点时轮子方向规定向北,绿色着地,然后滚动到终点,要求绿色着地,但是方向不做要求,问能不能做到,能的话输出最小时间
用一个结构体表示状态,x,y,d,c,t,分别是坐标(即行列),当前方向(0123表示上右下左),当前颜色,时间
然后用四维数组标记vis[x][y][d][c]来标记状态,这个很容易想到,仔细想想吧不说了
因为求最短时间,显然应该用bfs,然后就开始bfs,bfs是以时间为标准的(第一次就是没搞清这个关系,过了几组数据交上次,WA,第二次改回来就通过了),把0秒的所有可能的状态都找出来入队(其实就是起始状态),然后把1秒所有可能的状态找出来入队,就这样bfs。然后注释写得比较详细,这里就不说了,看代码应该也能懂
#include <cstdio> #include <cstring> #include <queue> using namespace std; #define MAX 30 #define D 4 //4个方向(北,东,南,西分别为0,1,2,3) #define C 5 //5中颜色(绿,黑,红,蓝,白分别为0,1,2,3,4) bool g[MAX][MAX]; bool vis[MAX][MAX][D][C]; //分别表示横纵坐标,方向,颜色 int sx,sy,ex,ey; //起点和终点的坐标 int n,m; struct node { int x,y; //坐标 int d; //方向 int c; //颜色 int t; //时间 }; struct node ans; queue <struct node> q; int dd[D][2]={ {-1,0},{0,1},{1,0},{0,-1} }; //四个方向滚动之后的坐标变化 void init() { memset(g,0,sizeof(g)); memset(vis,0,sizeof(vis)); for(int i=0; i<=m+1; i++) //迷宫的外围上下两边沿不能访问 g[0][i]=g[n+1][i]=1; for(int i=0; i<=n+1; i++) //迷宫的外围左右两边沿不能访问 g[i][0]=g[i][m+1]=1; return ; } void input() { for(int i=1; i<=n; i++) { char s[MAX]; scanf("%s",s+1); for(int j=1; j<=m; j++) if(s[j]=='#') g[i][j]=1; else if(s[j]=='S') { sx=i; sy=j;} else if(s[j]=='T') { ex=i; ey=j;} } /* for(int i=0; i<=n+1; i++) { for(int j=0; j<=m+1; j++) printf("%d ",g[i][j]); printf("\n"); } printf("%d %d\n%d %d\n",sx,sy,ex,ey); */ return ; }
/* void print_node(struct node t) //仅供测试 { printf("坐标: %d %d",t.x,t.y); printf(" 方向: %d",t.d); printf(" 颜色: %d",t.c); printf(" 时间: %d",t.t); printf("\n"); return ; }
*/ int BFS() { int FIND,x,y,d,c,t; struct node t1,t2; while(!q.empty()) q.pop(); //第一个节点的信息 t1.x=sx; //坐标就是起点坐标 t1.y=sy; //坐标就是起点坐标 t1.d=0; //起点方向规定向北 t1.c=0; //起点颜色规定绿色 t1.t=0; //地点时间为0 vis[sx][sy][0][0]=1; //这个状态已经用过 q.push(t1); //起点入队 FIND=0; //标记是否成功 while(!q.empty()) { t1=q.front(); //读取队头元素的信息 q.pop(); //队头元素出队 //print_node(t1); if(t1.x==ex && t1.y==ey && t1.c==0) //来到终点并且颜色为绿色 { ans=t1; FIND=1; break; } //原地顺时针旋转 x=t2.x=t1.x; y=t2.y=t1.y; d=t2.d=(t1.d+1)%4; c=t2.c=t1.c; t=t2.t=t1.t+1; if(!vis[x][y][d][c]) { vis[x][y][d][c]=1; q.push(t2); } //原地逆时针旋转 x=t2.x=t1.x; y=t2.y=t1.y; d=t2.d=(t1.d+3)%4; c=t2.c=t1.c; t=t2.t=t1.t+1; if(!vis[x][y][d][c]) { vis[x][y][d][c]=1; q.push(t2); } //第一次就是把原地的3种旋转都放进去(即转180也放进去),是错的 //因为转动180度用时是2秒,不是按照时间来bfs,要严格按照时间来bfs //向当前方向移动 x=t2.x=t1.x+dd[t1.d][0]; //计算新的坐标 y=t2.y=t1.y+dd[t1.d][1]; d=t2.d=t1.d; //方向不变 c=t2.c=(t1.c+1)%5; //新的颜色 t=t2.t=t1.t+1; //时间+1 if(g[x][y]) continue; //该点不能访问 if(!vis[x][y][d][c]) //该状态没有被用过 { vis[x][y][d][c]=1; q.push(t2); } } return FIND; } int main() { int T=0; while(scanf("%d%d",&n,&m)!=EOF && n && m) { T++; init(); input(); if(T>1) printf("\n"); printf("Case #%d\n",T); if(BFS()) printf("minimum time = %d sec\n",ans.t); else printf("destination not reachable\n"); } return 0; }