CCF CSP 202206-2寻宝大冒险[带注释满分]

博客涉及C++和C语言相关内容,重点在于算法方面。C++和C语言是重要的编程语言,在算法实现上有广泛应用,能解决各类信息技术问题。
#include<iostream>
#include<map>
#include<set>
using namespace std;
set<pair<int,int>> lht;
int B[50+5][50+5];
typedef set<pair<int,int>>::iterator Iterator;
int main(){
    int n;//树的棵树
    int L;//绿化图的大小
    int S;//藏宝图的大小
    //依次表示绿化图中树的坐标 
    cin>>n>>L>>S;
    for(int i=0;i<n;i++) {
        int x,y;//树的坐标
        cin>>x>>y;
        pair<int,int> node = make_pair(x,y);
        lht.insert(node);
    }
    //输入完整的藏宝图 
    for(int i=S;i>=0;i--){
        for(int j=0;j<=S;j++){
            cin>>B[i][j];
        }
    }
    //对绿化图中的每棵树进行检测 
    int count = 0;
    for(Iterator it = lht.begin();it!=lht.end();it++){
        pair<int,int> node = *it;//绿化图中的某棵树
        int x = node.first;
        int y = node.second;
//        cout<<"绿化图中的树坐标x= "<<x<<" y= "<<y<<endl;
        bool flag = true;
        //以绿化图某棵树[x,y]作为原点,与藏宝图中的B[0][0]重合,遍历藏宝图 
        for(int i=0;i<=S;i++){
            for(int j=0;j<=S;j++){
                int A_x = x+i;
                int A_y = y+j;
//                cout<<"试探绿化图A_x= "<<A_x<<"A_y= "<<A_y<<endl;
                if(A_x>L || A_y>L) flag = false;//藏宝图右上角超出绿化图边界 
                pair<int,int> Anode = make_pair(A_x,A_y);
                if(lht.find(make_pair(A_x,A_y))==lht.end()){
//                    cout<<"试探绿化图A_x= "<<A_x<<"A_y= "<<A_y<<"此处不是树"<<endl;
                    if(B[i][j]==1) //藏宝图是树 
                        flag = false;
                }else{
                    if(B[i][j]!=1){
                            flag = false;                    
                    }
                }
            }
            if(flag==false) break;
        }
        if(flag) count++; 
    }
    cout<<count<<endl;
    
    //输出藏宝图的正序 
//    for(int i=0;i<=S;i++){
//        for(int j=0;j<=S;j++){
//            cout<<B[i][j]<<" ";
//        }
//        cout<<endl;
//    }
    return 0;
}
### 解题思路 本题的目的是判断绿化图中是否存在与藏宝图完全匹配的区域。匹配的条件是:藏宝图中的每个 `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)`。 ### 测试用例与边界条件 - **边界条件**:确保藏宝图不会超出绿化图的边界。 - **测试用例**:包括多个藏宝图和绿化图的组合,验证代码的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值