~1 ccf 2022-06-2 寻宝!大冒险!

该博客探讨了一道编程题,题目涉及矩阵遍历和判断条件。输入为两个矩阵,一个表示藏宝图,一个表示地图,目标是找出能完全覆盖藏宝图的起点。题目关键在于矩阵的下标处理和遍历检查,同时注意边界条件和矩阵元素匹配。解决方案需要考虑矩阵坐标与藏宝图的关系,以及如何有效地检查每个可能的起点。

题目描述

在这里插入图片描述

输入

在这里插入图片描述

输出

在这里插入图片描述

样例输入

样例一:

5 100 2
0 0
1 1
2 2
3 3
4 4
0 0 1
0 1 0
1 0 0

样例二:

5 4 2
0 0
1 1
2 2
3 3
4 4
0 0 0
0 1 0
1 0 0

样例输出

样例一:
3
样例二:
0

子任务

在这里插入图片描述

源代码

#include <iostream>
#include <vector>
#include <set>

using namespace std;


int main() {
    int n, L, s;
    cin >> n >> L >> s;
    vector<pair<int, int>> v(n);
    set<pair<int, int>> set;
    for (int i = 0; i < n; i++) {
        cin >> v[i].first >> v[i].second;
        set.insert(v[i]);
    }
    vector<vector<int>> f(s + 1, vector<int>(s + 1));
    for (int i = s; i >= 0; i--) {
        for (int j = 0; j <= s; j++) {
            cin >> f[i][j];
        }
    }

    int ret = 0;
    for (int i = 0; i < n; i++) {
        int r = v[i].first;
        int c = v[i].second;
        bool check = true;
//        若当前点开始的矩阵不足以包含整个藏宝图
        if (r + s > L || c + s > L)
            check = false;
        for (int j = r, tr = 0; j <= r + s && check && tr <= s; j++, tr++) {
            for (int k = c, tc = 0; k <= c + s && check && tc <= s; k++, tc++) {
                if (f[tr][tc]) {
                    if (set.find({j, k}) == set.end()) {
                        check = false;

                    }

                } else {
                    if (set.find({j, k}) != set.end()) {
                        check = false;

                    }

                }
            }
        }
        if (check)
            ret++;
    }
    cout << ret;
    return 0;
}

关于这题

1.注意矩阵的下标,不是按着顺序来的。
2.提交代码时,选择CPP11或CPP14
3.当前点不能与藏宝图左下角对应分三种情况:
(1)当前点开始的矩阵不足以包含整个藏宝图
(2)藏宝图中某点有树,地图中对应位置没有树
(3)地图中某点有树,藏宝图对应位置没有树

### 解题思路 本题的目的是判断绿化图中是否存在与藏宝图完全匹配的区域。匹配的条件是:藏宝图中的每个 `1` 的位置在绿化图中也必须是 `1`,并且藏宝图不能超出绿化图的边界。 #### 数据结构与算法选择 - **二维数组**:使用二维数组存储绿化图和藏宝图。 - **暴力枚举**:枚举绿化图中每个点作为藏宝图左下角的可能位置,然后检查藏宝图是否能完全匹配。 - **优化检查**:通过提前记录藏宝图中 `1` 的数量,以及在匹配过程中统计匹配成功的 `1` 数量,减少不必要的计算。 ### C++ 满分代码实现 ```cpp #include <iostream> #include <vector> using namespace std; int main() { int n, L, S; cin >> n >> L >> S; // 存储绿化图中的点 vector<vector<int>> A(L + 1, vector<int>(L + 1, 0)); for (int i = 0; i < n; ++i) { int x, y; cin >> x >> y; A[x][y] = 1; } // 存储藏宝图 vector<vector<int>> B(S + 1, vector<int>(S + 1, 0)); for (int i = S; i >= 0; --i) { for (int j = 0; j <= S; ++j) { cin >> B[i][j]; } } int count = 0; // 枚举绿化图中每个点作为藏宝图的左下角 for (int x = 0; x <= L; ++x) { for (int y = 0; y <= L; ++y) { bool match = true; int match_count = 0; int target_count = 0; // 统计藏宝图中1的总数 for (int i = 0; i <= S; ++i) { for (int j = 0; j <= S; ++j) { if (B[i][j] == 1) { target_count++; } } } // 检查藏宝图是否可以匹配绿化图 for (int i = 0; i <= S; ++i) { for (int j = 0; j <= S; ++j) { if (B[i][j] == 1) { if (x + i > L || y + j > L || A[x + i][y + j] != 1) { match = false; break; } match_count++; } } if (!match) break; } if (match && match_count == target_count) { count++; } } } cout << count << endl; return 0; } ``` ### 代码解析 1. **输入处理**:首先读取输入数据,包括绿化图的点、藏宝图的大小和内容。 2. **匹配检查**:通过双重循环枚举绿化图中每个点作为藏宝图的左下角,然后检查藏宝图是否能完全匹配。 3. **效率优化**: - 提前统计藏宝图中 `1` 的数量。 - 在匹配过程中,一旦发现不匹配的情况立即跳出循环。 - 只有当匹配成功的 `1` 数量与藏宝图中的 `1` 数量相等时,才认为匹配成功。 ### 时间复杂度分析 - **枚举复杂度**:`O(L^2)`,其中 `L` 是绿化图的大小。 - **匹配复杂度**:`O(S^2)`,其中 `S` 是藏宝图的大小。 - **总复杂度**:`O(L^2 * S^2)`,在数据范围内是可接受的。 ### 空间复杂度分析 - 使用两个二维数组存储绿化图和藏宝图,空间复杂度为 `O(L^2 + S^2)`。 ### 测试用例与边界条件 - **边界条件**:确保藏宝图不会超出绿化图的边界。 - **测试用例**:包括多个藏宝图和绿化图的组合,验证代码的正确性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值