蓝桥-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 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起