SDUT2156 Fairy tale(第一届省赛题目)(模拟)

题目连接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2156

题意大概:一个迷宫,每个用WESN表示,每一个时刻都会发生变化,变化规律为E to W, W to S, S to N, and N to E.

人开始的位置在(0,0)宝藏开始的位置在右下角。

宝藏每一个时间段都会跟着迷宫上的字母移动一格,越界则停落原处。

每一个时间段:

1.都会跟着迷宫上的字母移动一格,越界则停落原处。

2.人会再根据自己的意愿走一步,按prefers to stay there than move, prefer E than W, W than N, and N than S的顺序,往离宝藏近的地方走。或者停留原处。

结束:1.找到宝藏 2.陷入循环,这个循环跟随地图的移动,所以要保证特定的时刻,字母相等。 3.大于100就跳出循环


解法:地图是来回变化的,开始看这题很难,就没做,就是一个模拟题,变化的地图总共有4种静态地图,并不用全部定义出来,

每次用的时候把改变时间变量(ttime)和当前地方的字幕就好。

每次所到的地方要先根据题意移动人和宝藏。

完了就是寻找出口,找出口题意已经明确给出了方法,按照优先方向变化的顺序寻找离宝藏最近的位置并向其移动,如果the same geometrical distance相同的集合距离,优先prefer E than W, W than N, and N than S这个顺序。

还有一个问题就是判断死循环。用了个5个变量的结构体每一次ttime都循环一遍,记录每一次的人的坐标,宝藏的坐标,以及当前时刻对4取余的结果,当本次遇到的5个变量和之前完全符合,就陷入了死循环。

如果看出是模拟题,感觉是可以做的,但做完之后发现,要想在比赛时A出这个题并不是很容易的,需要很严谨的逻辑,而且这道题意也是很难理解透彻的,做这个断断续续也用的半天的时间,但感觉这种东西是很好练的,需要的就是多刷题,多多去理解这些题,把大脑关于这种东西的神经纤维练得很厚,覆盖满髓鞘质,就会变得熟练顺手。

顺便说一句,SDUT的测试数据很水,没有死循环和超100的测试数据。


#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int Map[31][31];
int dis[4][2]={0,1,0,-1,1,0,-1,0};
int dis_p[4][2]={0,1,0,-1,1,0,-1,0};
//dui ying E W S N
int n;
int t_x,t_y,ok,ttime,x,y;

struct Coor
{
    int px,py,tx,ty,sp;
}cr[1001];
bool better(int x,int y,int xx,int yy){
    return (x-t_x)*(x-t_x)+(y-t_y)*(y-t_y) < (xx-t_x)*(xx-t_x)+(yy-t_y)*(yy-t_y);
}
bool outMap(int x,int y){
    if(x<0 || y<0 || y>=n || x>=n) return 1;
    return 0;
}
bool judge_re()
{
    int i;
    for(i=0;i<ttime;++i)
        if(cr[i].px==x&&cr[i].py==y&&cr[i].tx==t_x&&cr[i].ty==t_y&&cr[i].sp==ttime%4)
        {
            ok=true;
            return true;
        }
    cr[i].px=x;cr[i].py=y;cr[i].tx=t_x;cr[i].ty=t_y;cr[i].sp==ttime%4;

    return false;
}
bool step(){

    int s1 = (Map[x][y]+ttime)%4;
    int s2 = (Map[t_x][t_y]+ttime)%4;
    if(judge_re()) return false;
    if(x == t_x && y == t_y) return true;

    int xx = x + dis[s1][0];
    int yy = y + dis[s1][1];
    if(!outMap(xx,yy)) { x=xx,y=yy; }

    xx=x,yy=y;
    for(int i=0;i<4;i++){
        if(outMap(x+dis_p[i][0],y+dis_p[i][1]) ) continue;
        if(better(x+dis_p[i][0],y+dis_p[i][1],xx,yy) ){
            xx=x+dis_p[i][0];
            yy=y+dis_p[i][1];
        }
    }
    x = xx, y = yy;

    //treasure
    int txx = t_x + dis[s2][0];
    int tyy = t_y + dis[s2][1];
    if(!outMap(txx,tyy)) { t_x=txx; t_y=tyy; }
    ++ttime;
    return false;
}
int main()
{
    char c;
    int  test=0;
    while(scanf("%d",&n)&&n){
      for(int i=0;i<n;i++)
        for(int j=0;j<n;j++){
            cin>>c;
            if(c=='E') Map[i][j]=0;
            if(c=='W') Map[i][j]=1;
            if(c=='S') Map[i][j]=2;
            if(c=='N') Map[i][j]=3;

        }
//     for(int i=0;i<n;i++){
//        for(int j=0;j<n;j++){
//            cout<<Map[i][j]<<" ";
//
//        }
//        puts("");
//     }
        t_x=n-1,t_y=n-1;
        ttime=0;
        ok=0;
        x=0,y=0;
        printf("Case %d:\n",++test);
        while(ttime < 100){
            if(step()){
                printf("Get the treasure! At step %d.\n", ttime); break;
            }
            if(ok){
                 printf("Impossible. At step %d.\n", ttime);      break;
            }
            if(ttime == 99){
                printf("Not sure.\n");                            break;
            }
        }
        puts("");
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值