FZU Fire Game
题意
一张图,两个起点, 遍历其中所有的#
点最少需要多少步。
TLE代码及其中可以优化的点
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
//#pragma GCC optimize(2)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ull unsigned long long
#define ll long long
#define rep(i, x, y) for(int i=x;i<=y;i++)
#define mms(x, n) memset(x, n, sizeof(x))
#define mmc(A, tree) memcpy(A, tree, sizeof(tree))
#define eps (1e-8)
#define PI (acos(-1.0))
#define INF (0x3f3f3f3f)
#define mod (ll)(1e9+7)
typedef pair<int, int> P;
int const N = 110;
char ch[N][N];
// TODO: 优化点1
// 这里使用了vis数组,标记该节点是否访问过,后面又使用了结构体Node来记录步数。
// 不难发现这两个点是可以合并的,当vis为初始值时即可标记出未访问过,此外的值即可标记为访问过。
// 注意,这里可以这样优化的条件是访问并更改vis的值之后就不会再次更改了,即一次得出的值即为目标值,否则,我们可能需要更新得到最优值,这种情况下使用这种方法就会使得vis值改变,满足continue条件从而导致不能继续优化。
bool vis[N][N];
// TODO: 优化点2
// 这里使用了vector,初始时想用这个来push,但是没必要好吧, 直接用数组就可以的。
vector<P> v(N);
int n, m;
int num = 0;
struct Node {
int x, y, cnt;
Node() :x(0), y(0), cnt(0) {}
Node(int x, int y, int cnt) : x(x), y(y), cnt(cnt) {}
};
// TODO: NOTE: 写到这里突然疑惑了一下直接用一个二维数组和两个一维数组哪个更快,查了一下发现没啥大的区别。
int f[4][2] = {
{0, 1},
{0, -1},
{-1, 0},
{1, 0},
};
// TODO: 优化点3
// 根据优化点1和2,这个函数中所有涉及到的点都可以需要更改。
int find(P a, P b) {
queue<Node> q;
q.push(Node(a.first, a.second, 0));
q.push(Node(b.first, b.second, 0));
int ret = 0;
while (!q.empty()) {
int x = q.front().x, y = q.front().y, cnt = q.front().cnt;
q.pop();
// 1.1. 这里可以去掉
if (vis[x][y]) continue;
else vis[x][y] = true;
// 因为用vis记录了到达的长度,所以比较可以放在find函数最后的for循环中
ret = max(ret, cnt);
for (int k = 0; k < 4; k++) {
int X = x + f[k][0], Y = y + f[k][1];
// 条件需要进行更改。
if (X < 0 || Y < 0 || X >= n || Y >= m || vis[X][Y] || ch[X][Y] != '#') continue;
q.push(Node(X, Y, cnt + 1));
}
}
for (int i = 0; i < num; i++) {
// 判断条件应当是等于INF
if (!vis[v[i].first][v[i].second]) return INF;
}
return ret;
}
void solve() {
num = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%s", ch[i]);
for (int j = 0; j < m; j++) {
if (ch[i][j] == '#') {
v[num].first = i, v[num++].second = j;
}
}
}
if (num <= 2) {
printf("%d", 0);
return;
}
int ans = INF;
// TODO: 优化点5
// 这里不仅是可以优化的,而且也是可以说写错了的点。
// 本意是遍历所有的`#`点,但是由于使用了size(),所以成了遍历所有的100个点,十分浪费。
for (int i = 0; i < v.size(); i++) {
// TODO: 优化点6
// 这里i和j都是从0开始,就会出现重复判断同样的两个起点的情况,即(x, y)和(y, x)这两种完全一样的情况。
// NOTE:遍历时注意所遍历的矩阵是否是对称矩阵,对称矩阵则遍历上三角即可。
for (int j = 0; j < v.size(); j++) {
mms(vis, false);
ans = min(ans, find(v[i], v[j]));
}
}
printf("%d", (ans == INF ? -1 : ans));
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
rep(_, 1, T) {
printf("Case %d: ", _);
solve();
puts("");
}
return 0;
}
AC代码
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
//#pragma GCC optimize(2)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ull unsigned long long
#define ll long long
#define rep(i, x, y) for(int i=x;i<=y;i++)
#define mms(x, n) memset(x, n, sizeof(x))
#define mmc(A, tree) memcpy(A, tree, sizeof(tree))
#define eps (1e-8)
#define PI (acos(-1.0))
#define INF (0x3f3f3f3f)
#define mod (ll)(1e9+7)
typedef pair<int, int> P;
int const N = 20;
char ch[N][N];
int vis[N][N];
P v[110];
int n, m;
int num = 0;
int f[4][2] = {
{0, 1},
{0, -1},
{-1, 0},
{1, 0},
};
int find(P a, P b) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
vis[i][j] = INF;
}
}
queue<P> q;
q.push(a);
q.push(b);
vis[a.first][a.second] = vis[b.first][b.second] = 0;
int ret = 0;
while (!q.empty()) {
int x = q.front().first, y = q.front().second;
q.pop();
for (int k = 0; k < 4; k++) {
int X = x + f[k][0], Y = y + f[k][1];
if (X < 0 || Y < 0 || X >= n || Y >= m || vis[X][Y] != INF || ch[X][Y] != '#') continue;
vis[X][Y] = vis[x][y] + 1;
q.push(P(X, Y));
}
}
for (int i = 0; i < num; i++) {
int x = v[i].first, y = v[i].second;
if (vis[x][y] == INF) return INF;
ret = max(ret, vis[x][y]);
}
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
rep(_, 1, T) {
printf("Case %d: ", _);
// cout << "Case " << _ << ": ";
num = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%s", ch[i]);
for (int j = 0; j < m; j++) {
if (ch[i][j] == '#') {
v[num].first = i, v[num++].second = j;
}
}
}
if (num <= 2) {
// cout << 0 << '\n';
printf("%d\n", 0);
continue;
}
int ans = INF;
for (int i = 0; i < num; i++) {
for (int j = i + 1; j < num; j++) {
ans = min(ans, find(v[i], v[j]));
}
}
// cout << (ans == INF ? -1 : ans) << '\n';
printf("%d\n", (ans == INF ? -1 : ans));
}
return 0;
}