FZU 2150 Fire Game

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值