蓝桥-13届-C++-B组-省赛-H题-扫雷
直达链接
感觉是很有意思的题目——如果我会做的话
模拟吗?模拟这个过程,怎么标记一颗雷已经被排除呢?三个元素的存储可能不得不一个二维数组,既然这样,干脆就添加一个标志位:是否已经排除(爆炸),但是每次都遍历的话,复杂度O(N*M)肯定超时
5个过,3个错,12个超时
#include<iostream> #include<vector> #include<math.h> using namespace std; int cnt = 0; vector<vector<int>> landmine; long long range; // 因为存在递归,所以不得不单独抽一个函数出来 void boom(int x, int y, int r) { for (int i = 0; i < landmine.size(); i++) { if (cnt == landmine.size()) break; range = pow(r, 2); // 注意这里的引爆不是双向的,A爆了能引爆B,但是B爆了不一定能引爆A if (landmine[i][0] == 0) { if (pow(x - landmine[i][1], 2) + pow(y - landmine[i][2], 2) < range) { cnt++; landmine[i][0]++; boom(landmine[i][1], landmine[i][2], landmine[i][3]); } } } } int main() { int n, m; cin >> n >> m; // 我们假设第一位是一个额外添加的标志位,0未排除,1已排除 vector<int> temp(4, 0); int x, y, r; // 获取所有的地雷列表 for (int i = 0; i < n; i++) { cin >> x >> y >> r; temp[1] = x; temp[2] = y; temp[3] = r; landmine.push_back(temp); } // 但是每次不管咋样,都要遍历一次地雷列表,检查状态并操作,是不是时间复杂度太高了 for (int k = 0; k < m; k++) { cin >> x >> y >> r; boom(x, y, r); } cout << cnt; return 0; }
关于超时的问题,关键是有没有可能在遍历递归的过程中,更改(删除元素)集合的容量
好我解决了3个错误的问题,在于<= range
这里在边线上也是会被引爆的,接下来就是超时的问题
#include<iostream> #include<vector> #include<math.h> using namespace std; vector<vector<int>> landmineRow; int cnt = 0; int range; // 因为存在递归,所以不得不单独抽一个函数出来 void boom(int x, int y, int r, vector<vector<int>>& landmine) { vector<int> boomed; vector<vector<int>> leftLanmine; for (int i = 0; i < landmine.size(); i++) { range = pow(r, 2); // 注意这里的引爆不是双向的,A爆了能引爆B,但是B爆了不一定能引爆A if (pow(x - landmine[i][0], 2) + pow(y - landmine[i][1], 2) <= range) boomed.push_back(i); else leftLanmine.push_back(landmine[i]); } landmineRow.assign(leftLanmine.begin(), leftLanmine.end()); cnt += boomed.size(); if (landmineRow.size() == 0) return; for (int i : boomed) boom(landmine[i][0], landmine[i][1], landmine[i][2], landmineRow); } int main() { int n, m; cin >> n >> m; // 我们假设第一位是一个额外添加的标志位,0未排除,1已排除 vector<int> temp(3, 0); int x, y, r; // 获取所有的地雷列表 for (int i = 0; i < n; i++) { cin >> x >> y >> r; temp[0] = x; temp[1] = y; temp[2] = r; landmineRow.push_back(temp); } // 但是每次不管咋样,都要遍历一次地雷列表,检查状态并操作,是不是时间复杂度太高了 for (int k = 0; k < m; k++) { cin >> x >> y >> r; boom(x, y, r, landmineRow); } cout << cnt; return 0; }
我努力尝试解决超时问题,但是问题没解决,反而一个都不对了,果然我还是该睡觉了,效率、状态太差
#include<iostream> #include<vector> #include<math.h> using namespace std; int range;// r的最大值也就是10,也就是说平方不超过100 // 因为存在递归,所以不得不单独抽一个函数出来 void boom(int x, int y, int r, vector<vector<int>>& landmine) { if (landmine.size() == 0) return; vector<int> boomed; vector<vector<int>> leftLandmine; for (int i = 0; i < landmine.size(); i++) { range = pow(r, 2); // 注意这里的引爆不是双向的,A爆了能引爆B,但是B爆了不一定能引爆A if (pow(x - landmine[i][0], 2) + pow(y - landmine[i][1], 2) <= range) boomed.push_back(i); else leftLandmine.push_back(landmine[i]); } for (int i : boomed) boom(landmine[i][0], landmine[i][1], landmine[i][2], leftLandmine); landmine.assign(leftLandmine.begin(), leftLandmine.end()); } int main() { int n, m; cin >> n >> m; vector<int> temp(3, 0); int x, y, r; vector<vector<int>> landmineRow; for (int i = 0; i < n; i++) { cin >> x >> y >> r; temp[0] = x; temp[1] = y; temp[2] = r; landmineRow.push_back(temp); } for (int k = 0; k < m; k++) { cin >> x >> y >> r; boom(x, y, r, landmineRow); } cout << n - landmineRow.size(); return 0; }
啊,我真的尽力了,怎么还是12个超时,超时一个没解决,我都已经动态更新地雷列表了
#include<iostream> #include<vector> #include<math.h> using namespace std; vector<vector<int>> landmineRow; int range;// r的最大值也就是10,也就是说平方不超过100 // 因为存在递归,所以不得不单独抽一个函数出来 void boom(int x, int y, int r, vector<vector<int>>& landmine) { if (landmine.size() == 0) return; vector<int> boomed; vector<vector<int>> leftLandmine; for (int i = 0; i < landmine.size(); i++) { range = pow(r, 2); // 注意这里的引爆不是双向的,A爆了能引爆B,但是B爆了不一定能引爆A if (pow(x - landmine[i][0], 2) + pow(y - landmine[i][1], 2) <= range) boomed.push_back(i); else leftLandmine.push_back(landmine[i]); } for (int i : boomed) boom(landmine[i][0], landmine[i][1], landmine[i][2], leftLandmine); // 这里的更新是给下一次除雷火箭用的,而不是给递归本身用的,递归本身用的是leftLandmine,这两个过程都已经是动态更新了为什么还是超时 for (int i : boomed) landmineRow.erase(landmineRow.begin() + i);// 为什么这么写不对?不是和下面那句等价吗 // landmine.assign(leftLandmine.begin(), leftLandmine.end());// 我觉得这句不对,上面那句是对的 } int main() { int n, m; cin >> n >> m; vector<int> temp(3, 0); int x, y, r; for (int i = 0; i < n; i++) { cin >> x >> y >> r; temp[0] = x; temp[1] = y; temp[2] = r; landmineRow.push_back(temp); } for (int k = 0; k < m; k++) { cin >> x >> y >> r; boom(x, y, r, landmineRow); } cout << n - landmineRow.size(); return 0; }
不行了,超时怎么解决,是不是只有换思路了,模拟必定超时
分析60%超时正好是题目给出的测试用例比例,也就是说我能过103但是过不了5*104
2023/3/7
题解得思路是这样的:
因为n的数量高达5*104,所以考虑连锁反应的话必定是超时的(但是不可能不判断吧,万一就有会被雷引爆而不是被火箭引爆的呢?)
#include<iostream> #include<map> #include<queue> using namespace std; int n, m; // C用来给每个点的雷数量计数,R用来记录每个点位置雷的最大半径 map<pair<int, int>, int> R, C; /* * 计算两点之间的距离 */ int distanse(int x1,int y1,int x2,int y2) { return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); } /* * 多源点BFS算法 */ int BFS() { int ans = 0; // 这是个什么数据结构?将坐标点pair和半径组成一个新pair,然后再构造一个队列 queue<pair<pair<int, int>, int>> Q; /* * 获取输入并构造火箭队列 */ for (int i = 0; i < m; i++) { int x, y, r; cin >> x>> y>>r; auto point = make_pair(x, y); Q.push(make_pair(point, r)); } while (!Q.empty()) { auto node = Q.front(); Q.pop(); int x = node.first.first, y = node.first.second, r = node.second; /* * 遍历以xy为圆心,r为半径的圆中的所有点 * 注意这里要包括在边界上的点 * 因为这里最多r=10,所以双层循环的最高复杂度也只有400 */ for (int i = x - r; i <= x + r; i++) { for (int j = y - r; j <= y + r; j++) { if (distanse(i, j, x, y) > r*r) continue;// 如果距离在引爆范围外 auto point = make_pair(i, j); /* * 如果该点存在炸雷,就记下该点的炸雷数 * 该炸雷就相当于新的排雷火箭 * 该点被引爆,所以从炸雷队列中排除 */ if (R.count(point)) { ans += C[point]; Q.push(make_pair(point, R[point])); R.erase(point); } } } } return ans; } int main() { cin >> n>> m; for (int i = 0; i < n; i++) { int x, y, r; cin >> x >> y >> r; auto point = make_pair(x, y); C[point] += 1; R[point] = max(R[point], r); } cout << BFS() << endl; return 0; }
这题的思路是什么?
和我之前的思路有什么区别?为什么我超时了它没有?
因为爆炸范围很小,所以它遍历的是每次引爆范围内的所有点,检查这些点有没有雷(通过hashmap达到了O(1)
),而不是去遍历所有的雷,看会不会被引爆
检查范围内点的数量级是400
检查所有类遍历一次最大是5*104
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/17009306.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了