2022.10.26 总结
1. 逐月 P5132
题意
有一个 \(n \times n\) 的房间,Bessie 在 \((1, 1)\) 处,这个房间是亮着灯的。
Bessie 害怕黑暗,她想要打开尽可能多的灯。
在一些房间中,她可以找到打开别的房间灯的开关,并且,她只能往自己周围四个房间走。
请你求出 Bessie 最多能打开多少个房间的灯。
思路
100 分
首先,这个题目很明显,是一个搜索。
那么,就需要考虑状态和转移是什么的问题了。
先看状态,很明显,是 \((x, y)\),也就是坐标。有一种转移很明显,就是往上下左右做转移,但是一个房间能否走不只是要看能不能走到,还要看有没有亮灯,所以这是第二种转移。
第一种转移实现很简单,主要是第二种。
首先得清楚一件事,你是绝对不能往回走的,因为如果可以往回走,那你就能这样走:\((1, 1)\) -> \((1, 2)\) -> \((1, 1)\) -> \((1, 2)\) -> \((1, 1) \dots\)。
但是如果是这样的一个样例的话:
3 6
1 1 1 2
2 1 2 2
1 1 1 3
2 3 3 1
1 3 1 2
1 3 2 1
在走到 \((1, 3)\) 时,会触发 \((2, 1)\) 的开关,但是,要想走到 \((2, 1)\),就得先到 \((1, 2)\),再到 \((1, 1)\),再去 \((2, 1)\),而点又是不能重复走的,所以,你需要知道:你走过的点都是可以再次走到的。根据这个,就可以得到解决问题的方法:枚举每个会被触发的房间,判断四周是否有走到过的房间,如果有,这个房间就是可以被走到的。
直接搜索就可以了。
时间复杂度
状态图遍历,每个房间只会被遍历一遍,\(O(n ^ 2)\)。
枚举被触发的房间,用 vector,\(O(m)\)。
总时间复杂度为 \(O(n ^ 2 + m)\)。
空间复杂度
有 \(n ^ 2\) 个 vector,\(O(n ^ 2)\)。
vector 总共会存放 \(m\) 个坐标,\(O(m)\)。
总空间复杂度为 \(O(n ^ 2 + m)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};
int n, m, ans;
bool f[N][N], vis[N][N];
struct C {
int x, y;
};
vector<C> v[N][N];
void dfs(int x, int y) {
if (x < 1 || x > n || y < 1 || y > n || !f[x][y] || vis[x][y]) {
return ;
}
vis[x][y] = 1;
for (int i = 0; i < v[x][y].size(); i++) {
bool flag = 0;
int xx = v[x][y][i].x, yy = v[x][y][i].y;
f[xx][yy] = 1;
for (int j = 0; j < 4; j++) {
int nx = xx + dx[j], ny = yy + dy[j];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && vis[nx][ny]) {
flag = 1;
break;
}
}
if (flag) {
dfs(xx, yy);
}
}
for (int i = 0; i < 4; i++) {
dfs(x + dx[i], y + dy[i]);
}
}
int main() {
freopen("lightson.in", "r", stdin);
freopen("lightson.out", "w", stdout);
cin >> n >> m;
while (m--) {
int x, y, a, b;
cin >> x >> y >> a >> b;
v[x][y].push_back({a, b});
}
f[1][1] = 1;
dfs(1, 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
ans += f[i][j];
}
}
cout << ans;
return 0;
}