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; }
posted @ 2012-11-14 15:13  Titanium  阅读(970)  评论(0编辑  收藏  举报