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才能走到这里。
}