洛谷P2895 [USACO 08FEB] Meteor Shower S 代码示例详解

P2895

一道广搜,看似普通实则巧妙的好题。

  • 对地图的限制是动态的。初始化的覆盖很有特点
  • 地图是开放的。(相对于闭环的经典地图中最短路的广搜问题)
#include <bits/stdc++.h>
using namespace std;
const int N = 305;
int t[N][N], n, x, y, z; 
bool vis[N][N];
struct pos
{
    int x, y, t;
    // pos(int _x, int _y, int _t) : x(_x), y(_y), t(_t) { }//在时间复杂度危险的时候,应该考虑删掉构造函数
    //经过测试吗,其实并不太影响orz
    //另外,估计复杂度的时候不要将时间和空间搞混了。第一遍把时间和空间的乘在一起,觉得很大很可怕
} tmp;//同时,删掉构造函数之后,我们就有了这样一个机动的tmp对象

const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
inline bool check(int tx, int ty, int tt)
//这个题目很特殊的一点,就是它的地图不是封闭的。如果时间够长,最终可以逃出n×n的矩阵
{
    return tx >= 0 && ty >= 0 && !vis[tx][ty] && (t[tx][ty] == -1 || t[tx][ty] > tt);
}

int main()
{
    cin >> n;
//流星雨的时空分布初始化
    memset(t, 0xff, sizeof t);//设置从未到过
	//思考:可以设置一个很大的值,然后我们的判断行为就变的一致,不用对-1进行特判了

    for (int i = 0; i < n; i++)
    {
        cin >> x >> y >> z;
        
        if (t[x][y] == -1 || t[x][y] > z) t[x][y] = z;
        //这个覆盖很有特点,先到先得。而可以更新的case集中在0~t中,所以
        
        for (int j = 0; j < 4; j++)//对焦土进行初始化
            if (check(x+dx[j], y+dy[j], z))
                t[x+dx[j]][y+dy[j]] = z;
    }
//队列初始化
    tmp.x = 0, tmp.y = 0, tmp.t = 0;
    queue<pos>q; q.push(tmp);vis[0][0] = true;
    //这个vis不如地图问题里那样对可解有关键性的意义。
    //因为有另一个限制,随时间流逝,对一个确定的点来说,就越不可能扩展随即被剪掉。
    //所以即使不用vis可以正确得到结果。但是时间大概在4倍左右
    
    if (t[0][0] == -1)
    {
        cout << 0 << endl; 
        return 0;
    }
//开始广搜
    while (!q.empty())
    {
        tmp = q.front(); q.pop();
	//pop尽量早点出现,先开始中间加了一句continue(不必要),就使得pop没有进行最终死循环了。
        for (int i = 0; i < 4; i++)
        {
            int tx = tmp.x + dx[i], ty = tmp.y + dy[i], tt = tmp.t+1;
            if (check(tx, ty, tt))
            {
                pos temp; temp.x = tx, temp.y = ty, temp.t = tt;
                q.push(temp);vis[tx][ty] = true;
                if (t[tx][ty]==-1)
                //需要保证其在第一象限之内,所以应该嵌套if
                {
                    cout << tt << endl;
                    return 0;
                }
            }
        }
    }
    cout << -1 << endl;//无解的case才能走到这里。
}

猜你喜欢

转载自blog.csdn.net/weixin_45502929/article/details/106785026