ccf游戏(c++100)

问题描述

  小明在玩一个电脑游戏,游戏在一个n×m的方格图上进行,小明控制的角色开始的时候站在第一行第一列,目标是前往第n行第m列。
  方格图上有一些方格是始终安全的,有一些在一段时间是危险的,如果小明控制的角色到达一个方格的时候方格是危险的,则小明输掉了游戏,如果小明的角色到达了第n行第m列,则小明过关。第一行第一列和第n行第m列永远都是安全的。
  每个单位时间,小明的角色必须向上下左右四个方向相邻的方格中的一个移动一格。
  经过很多次尝试,小明掌握了方格图的安全和危险的规律:每一个方格出现危险的时间一定是连续的。并且,小明还掌握了每个方格在哪段时间是危险的。
  现在,小明想知道,自己最快经过几个时间单位可以达到第n行第m列过关。

输入格式

  输入的第一行包含三个整数nmt,用一个空格分隔,表示方格图的行数n、列数m,以及方格图中有危险的方格数量。
  接下来t行,每行4个整数rcab,表示第r行第c列的方格在第a个时刻到第b个时刻之间是危险的,包括ab。游戏开始时的时刻为0。输入数据保证rc不同时为1,而且当rnc不为m。一个方格只有一段时间是危险的(或者说不会出现两行拥有相同的rc)。

输出格式

  输出一个整数,表示小明最快经过几个时间单位可以过关。输入数据保证小明一定可以过关。

样例输入

3 3 3
2 1 1 1
1 3 2 10
2 2 2 10

样例输出

6

样例说明

  第2行第1列时刻1是危险的,因此第一步必须走到第1行第2列。
  第二步可以走到第1行第1列,第三步走到第2行第1列,后面经过第3行第1列、第3行第2列到达第3行第3列。

评测用例规模与约定

  前30%的评测用例满足:0 < nm ≤ 10,0 ≤ t < 99。
  所有评测用例满足:0 < nm ≤ 100,0 ≤ t < 9999,1 ≤ r ≤ n,1 ≤ c ≤ m,0 ≤ a ≤ b ≤ 100。


这是一道迷宫题,祸害许多人的妖艳贱货小明把一道迷宫题玩出了新高度--__--

迷宫在每个时刻的布局是会变的,有的点能走有的不能走,超级有毒

很明显的BFS

可以把四个方向设置成一个结构体数组,方便遍历,需要判断的条件是如果没有到达终点,那么上下左右的位置判断,如果没有毒,可以走,并且在第t秒的时候,没有在队列里面,防止队列里有重复的点(超级重要!!),然后判断一下上下左右有没有超出边界,嗯!没有,那么可以加入队列.

 

但是楼主踩了好多坑...

开始没有加是否超边界的条件,debug一下就找出来了

但是!!!一直说我超时!!我没有想到应该判断在同一时间有可能有相同的点会加进来!只是想到貌似离散老师讲一个算法时有一种情况是除非所有的路都不能走,否则不走那条路,然后...(自以为机智的)楼主设定除非其他路都有毒,否则不走上一个走过的点,结果还是超时!!只有50分

我不甘心!!

还能dfs一下!!

完蛋

连50都没有.

 

然后无计可施,只能看看大神的操作,发现其实它并不排斥已经走过的点,排斥的是我在第t秒已经把A点加进去了,A点又重复压队列!!对,就是这个导致我超时!!,于是楼主改呀!

还是50...

这个就可能是BFS之外的操作超时了,看看题目,其实大的是那个9999的有毒点的输入,楼主恍然大悟,因为我在判断有毒的时候,因为用vector存储那些点,一天到晚遍历9999,不超时才怪,那就想想有没有什么可以立刻保证知道该点有没有毒呢?方法昭然若现,就是数组嘛,只不过用的是结构体数组,存储了有毒的时刻,可以直接访问该点而不用遍历了.

 

所以就100了.

嗯,所以惯性思维要不得,罪魁祸首就是楼主下意识就用vector来存储有毒点了,其实本题的点的数目不大,完全可以用数组,不必害怕占用太大空间什么的...

OK.

上代码

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <set>
#define maxn 10000
using namespace std;
int n,m;
//int maze[100][100];
int counTime = 0;
int lasTime[101][101][300];

//坐标
struct Site{
    int xx;
    int yy;
    int time;
    Site(int a,int b,int t){
        xx = a;
        yy = b;
        time = t;
    }
};


//方向
struct dire{
    int x;
    int y;
    dire(int a,int b){
        x = a;
        y = b;
    }
};

//上左下右
struct dire dires[4] = {{-1,0},{0,-1},{1,0},{0,1}};

struct Node{
    int aTime;
    int bTime;
    Node(int a,int b)
    {
        aTime = a;
        bTime = b;
    }
    Node(){}
};

struct Node nodes[101][101];


struct Point{
    int x;
    int y;
    Point(int a,int b)
    {
        x = a;
        y = b;
    }
    friend bool operator <(Point a,Point b)
    {
        if(a.x!=b.x)
            return a.x>b.x;
        else
            return a.y>b.y;
    }

};


set<Point>path;

//看一下在nodes中有没有毒
bool safe(int nowX,int nowY,int t)
{
    if(nodes[nowX][nowY].aTime<=t&&t<=nodes[nowX][nowY].bTime)
        return 0;
    else
        return 1;
}



bool judge(int x,int y)
{
    return x>=1&&x<=n && y>=1 && y <=m;
}




void BFS(int row,int col,int t)
{
    queue<Site>q;
    q.push(Site(row,col,t));
    path.insert(Point(row,col));
    lasTime[row][col][t] = 0;//x y t
    //div(1,1,0);

    int flag = 0;
    while(!q.empty()&&!flag)
    {
        Site st = q.front();
        q.pop();
        int nowX = st.xx;
        int nowY = st.yy;
        int T = st.time+1;
        //加方向
        int same = 0;//看看有没有已经访问过的点
        int ok = 0;//看看有没有符合的下一个方向
        int beforeX,beforeY;
        int nowXTemp,nowYTemp;
        for(int i = 0;i<4;i++)
        {
            nowXTemp = nowX+dires[i].x;
            nowYTemp = nowY+dires[i].y;
            if( !(nowXTemp>=1&&nowXTemp<=n && nowYTemp>=1 && nowYTemp <=m) )
            {
                continue;
            }
            if(safe(nowXTemp,nowYTemp,T))
            {
                if(nowXTemp== n&&nowYTemp == m)
                {
                    flag = 1;
                    cout<<T<<endl;
                    exit (0);
                }
                else if(path.count(Point(nowXTemp,nowYTemp)))//如果和之前的相同的话
                {
                    beforeX = nowXTemp;
                    beforeY = nowYTemp;
                    same = 1;
                    continue;
                }
                else//如果不相同的话
                {
                    if(lasTime[nowXTemp][nowYTemp][T]==0)
                    {
                        ok = 1;
                        lasTime[nowXTemp][nowYTemp][T] = 1;
                        path.insert(Point(nowXTemp,nowYTemp));
                        q.push(Site(nowXTemp,nowYTemp,T));
                    }

                }
            }
        }
        if(same && !ok && !lasTime[beforeX][beforeY][T])
        {
            lasTime[beforeX][beforeY][T] = 1;
            q.push(Site(beforeX,beforeY,T));
        }

    }
    /**   这是一段更简洁的代码,上面的是楼主防止走上一点的鸡肋代码,建议学习注释里的更简洁.
    queue<Site>q;
    q.push(Site(row,col,t));
    lasTime[row][col][t] = 1;//在t时间内访问过了
    while(!q.empty())
    {
        Site st = q.front();
        q.pop();
        int nowX = st.xx;
        int nowY = st.yy;
        if(nowX == n && nowY == m)
        {
            counTime = st.time;
            break;
        }
        int T = st.time+1;
        //加方向
        int nowXTemp,nowYTemp;
        for(int i = 0;i<4;i++)
        {
            nowXTemp = nowX+dires[i].x;
            nowYTemp = nowY+dires[i].y;
            if(judge(nowXTemp,nowYTemp) && safe(nowXTemp,nowYTemp,T) && !lasTime[nowXTemp][nowYTemp][T])//没有超过的坐标
            {
                    lasTime[nowXTemp][nowYTemp][T] = 1;
                    q.push(Site(nowXTemp,nowYTemp,T));
            }
        }
    }**/
}

int main()
{

    int t;
    cin>>n>>m>>t;
    int r,c,a,b;
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=m;j++)
    {
        nodes[i][j] = Node(-1,-1);
    }
    for(int i = 0;i<t;i++)
    {
        scanf("%d%d%d%d",&r,&c,&a,&b);
        nodes[r][c].aTime = a;
        nodes[r][c].bTime = b;
    }
    memset(lasTime,0,sizeof(lasTime));
   // div(1,1,0);
    BFS(1,1,0);
    //开始

    //cout<<counTime;
    return 0;
}

/**

3 3 3
 2 1 1 1
 1 3 2 10
 2 2 2 10
 **/

好啦!

不要被卡,不要妄自菲薄,要坚信自己是要一步一步地走在那一万小时定律上的,即使步履维艰,颤颤巍巍,也没有放弃的自己.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值